MS Graph create event 400 bad request - microsoft-graph-api

I have code that get's the default calendar and stores the id in a variable called calendar id. I then I then get a list of availabilities (which are events in our system) the end time and the start time are recorded in utc and I want to put those events into an office 365 calendar.
This is my code which is generating and 400 Bad request. Does anyone have any idea what I am doing wrong?
using (HttpClient httpClient = new HttpClient())
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", msBearerToken);
var callJson = new
{
Subject = "Booking",
Body = new ItemBody
{
ContentType = BodyType.Html,
Content = "Available"
},
Start = new DateTimeTimeZone
{
DateTime = availabilitySummery.StartDateUTC.ToString(),
TimeZone = "Europe/London"
},
End = new DateTimeTimeZone
{
DateTime = availabilitySummery.EndDateUTC.ToString(),
TimeZone = "Europe/London"
}
};
string path = $"/me/calendars/{calendarId}/events";
// string path = "/me/calendars/events";
path = "https://graph.microsoft.com/v1.0" + path;
HttpResponseMessage responseMessage = await httpClient.PostAsJsonAsync(path, callJson);}

Date should be ISO8601 formatted.
Replace .ToString() by .ToString("o") when you want to convert dates to string.
Ref: The round-trip ("O", "o") format specifier
And createdDateTime property of event object

Update: This worked:
using (HttpClient httpClient = new HttpClient())
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", msBearerToken);
var callJson = new
{
Subject = "Booking",
Body = new
{
ContentType = BodyType.Html.ToString(),
Content = "Available"
},
Start = new
{
DateTime = availabilitySummery.StartDateUTC.ToString("yyyy-MM-ddTHH:mm:ss"),
TimeZone = "GMT Standard Time"
},
End = new
{
DateTime = availabilitySummery.EndDateUTC.ToString("yyyy-MM-ddTHH:mm:ss"),
TimeZone = "GMT Standard Time"
}
};
string path = $"/me/calendars/{calendarId}/events";
string jsoncall = JsonConvert.SerializeObject(callJson);
path = "https://graph.microsoft.com/v1.0" + path;
HttpResponseMessage responseMessage = await httpClient.PostAsJsonAsync(path, callJson);
string content = await responseMessage.Content.ReadAsStringAsync();
if (!responseMessage.IsSuccessStatusCode)
{
return false;
}
}

Related

Bad request when posting to OData Data Entity in Dynamics 365

I've created a public Data Entity in dynamics with the following fields:
I keep getting a bad request response, but I'm not sure why.
I've tried to make a POST request in two ways:
1.
HireAction hireAction = new HireAction() { CompanyName = "DEMF", MovieId = "DEMF-000000014", HireActionStatus = "Created" };
string jsonMessage = JsonConvert.SerializeObject(hireAction);
using (HttpClient client = new HttpClient())
{
HttpRequestMessage requestMessage = new
HttpRequestMessage(HttpMethod.Post, "MyDynamicsEnvironmentName/data/HireActions?cross-company=true");
requestMessage.Content = new StringContent(jsonMessage, Encoding.UTF8, "application/json");
requestMessage.Headers.Add("Authorization", AuthResult.AuthorizationHeader);
HttpResponseMessage response = client.SendAsync(requestMessage).Result;
if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
//Logic
}
}
var url = "MyDynamicsEnvironmentName/data/HireActions?cross-company=true";
var req = HttpWebRequest.Create(url);
req.Method = "POST";
req.ContentType = "application/json";
req.Headers["Authorization"] = AuthResult.AuthorizationHeader;
HireAction hireAction = new HireAction() { CompanyName = "DEMF", MovieId = "DEMF-000000014", HireActionId = "12345", HireActionStatus = "Created" };
var jsonSettings = new JsonSerializerSettings
{
DateTimeZoneHandling = DateTimeZoneHandling.Local
};
var postString = "CompanyName='DEMF'" + "&MovieId='DEMF-000000014'" + "&HireActionId=132&HireActionStatus='Created'";
var data = JsonConvert.SerializeObject(postString, jsonSettings);
var bytes = Encoding.Default.GetBytes(postString);
var newStream = req.GetRequestStream();
newStream.Write(bytes, 0, bytes.Length);
newStream.Close();
using (var resp = req.GetResponse())
{
var results = new StreamReader(resp.GetResponseStream()).ReadToEnd();
}
Some keypoints:
-Of course you'd replace MyDynamicsEnvironmentName with the URL for the environment. The URL is correct and verified however, by the fact that GET requests do work
-The Authresult.AuthorizationHeader contains a valid token, also validated by working GET requests
As said before, both of these result in a bad request. Does someone know what is wrong or missing?

Using webforms with API - returns null values

Can anybody help me?
This code work fine with no parameter:
private void PopulateGridView()
{
string apiUrl = apiurl + "local_stud_listgrupmenu";
string inputJson = (new JavaScriptSerializer()).Serialize(input);
WebClient client = new WebClient();
client.Headers["Content-type"] = "application/json";
client.Headers[HttpRequestHeader.ContentType] = "application/json";
client.Encoding = Encoding.UTF8;
string json2 = client.UploadString(apiUrl,"POST");
Response.Write("output:" + json2.ToString());
}
but this code below return null with post parameter, what wrong my code :)
private void crudinsert()
{
string data;
string apiUrl = apiurl + "ins_rec_crudparentmenu";
string x = "";
var vm = new { mod = "0", moduldesc ="test'", modulurl = "tesx.aspx", idparent= "0" };
using (var clien2 = new WebClient())
{
var dataString = (new JavaScriptSerializer()).Serialize(vm);
client.Headers.Add(HttpRequestHeader.ContentType, "application/json");
x = client.UploadString(new Uri(apiUrl), "POST", dataString);
}
Response.Write("output:"+x);
}

Create team in GraphAPI returns always null

I am using GraphAPI SDK to create a new Team in Microsoft Teams:
var newTeam = new Team()
{
DisplayName = teamName,
Description = teamName,
AdditionalData = new Dictionary<string, object>()
{
{"template#odata.bind", "https://graph.microsoft.com/v1.0/teamsTemplates('standard')"}
},
Members = new TeamMembersCollectionPage()
{
new AadUserConversationMember
{
Roles = new List<String>()
{
"owner"
},
AdditionalData = new Dictionary<string, object>()
{
{"user#odata.bind", $"https://graph.microsoft.com/v1.0/users/{userId}"}
}
}
}
};
var team = await this.graphStableClient.Teams
.Request()
.AddAsync(newTeam);
The problem is that I get always null. According documentation this method returns a 202 response (teamsAsyncOperation), but the AddAsync method from SDK returns a Team object. Is there any way to get the tracking url to check if the team creation has been finished with the SDK?
Documentation and working SDK works different... As they wrote in microsoft-graph-docs/issues/10840, we can only get the teamsAsyncOperation header values if we use HttpRequestMessage as in contoso-airlines-teams-sample. They wrote to the people who asks this problem, look to the joined teams :)) :)
var newTeam = new Team()
{
DisplayName = model.DisplayName,
Description = model.Description,
AdditionalData = new Dictionary<string, object>
{
["template#odata.bind"] = $"{graph.BaseUrl}/teamsTemplates('standard')",
["members"] = owners.ToArray()
}
};
// we cannot use 'await client.Teams.Request().AddAsync(newTeam)'
// as we do NOT get the team ID back (object is always null) :(
BaseRequest request = (BaseRequest)graph.Teams.Request();
request.ContentType = "application/json";
request.Method = "POST";
string location;
using (HttpResponseMessage response = await request.SendRequestAsync(newTeam, CancellationToken.None))
location = response.Headers.Location.ToString();
// looks like: /teams('7070b1fd-1f14-4a06-8617-254724d63cde')/operations('c7c34e52-7ebf-4038-b306-f5af2d9891ac')
// but is documented as: /teams/7070b1fd-1f14-4a06-8617-254724d63cde/operations/c7c34e52-7ebf-4038-b306-f5af2d9891ac
// -> this split supports both of them
string[] locationParts = location.Split(new[] { '\'', '/', '(', ')' }, StringSplitOptions.RemoveEmptyEntries);
string teamId = locationParts[1];
string operationId = locationParts[3];
// before querying the first time we must wait some secs, else we get a 404
int delayInMilliseconds = 5_000;
while (true)
{
await Task.Delay(delayInMilliseconds);
// lets see how far the teams creation process is
TeamsAsyncOperation operation = await graph.Teams[teamId].Operations[operationId].Request().GetAsync();
if (operation.Status == TeamsAsyncOperationStatus.Succeeded)
break;
if (operation.Status == TeamsAsyncOperationStatus.Failed)
throw new Exception($"Failed to create team '{newTeam.DisplayName}': {operation.Error.Message} ({operation.Error.Code})");
// according to the docs, we should wait > 30 secs between calls
// https://learn.microsoft.com/en-us/graph/api/resources/teamsasyncoperation?view=graph-rest-1.0
delayInMilliseconds = 30_000;
}
// finally, do something with your team...
I found a solution from another question... Tried and saw that it's working...

Graph API bug changing recurrence from "noEnd" to "numbered"

I have an event in Outlook with an attendee that uses Google calendar. When I change the event recurrence range type using the graph API from "noEnd" to "numbered", the google attendee's event does not get updated.
Here is the code I am using to set the recurrence as "noEnd":
public async System.Threading.Tasks.Task SetDailyRecurrenceForever(string ExternalID, string CalendarRefreshToken)
{
var tmpEvent = new Microsoft.Graph.Event
{
Recurrence = new PatternedRecurrence
{
Pattern = new RecurrencePattern
{
Type = RecurrencePatternType.Daily,
Interval = 1,
FirstDayOfWeek = Microsoft.Graph.DayOfWeek.Sunday,
Index = WeekIndex.First
},
Range = new RecurrenceRange
{
Type = RecurrenceRangeType.NoEnd,
StartDate = new Microsoft.Graph.Date(2020,10,6),
RecurrenceTimeZone = "Central Standard Time",
NumberOfOccurrences = 0
}
}
};
var graphClient = await MicrosoftAuthenticationProvider.GetGraphClient(CALENDAR_CLIENT_ID, CALENDAR_CLIENT_SECRET, CALENDAR_REDIRECT_URI, CALENDAR_ACCESS_SCOPES, CalendarRefreshToken)
.ConfigureAwait(false);
await graphClient.Me.Events[ExternalID]
.Request()
.UpdateAsync(tmpEvent)
.ConfigureAwait(false);
}
Here is the code I am using to set the recurrence as "numbered":
public async System.Threading.Tasks.Task SetDailyRecurrenceForFiveDays(string ExternalID, string CalendarRefreshToken)
{
var tmpEvent = new Microsoft.Graph.Event
{
Recurrence = new PatternedRecurrence
{
Pattern = new RecurrencePattern
{
Type = RecurrencePatternType.Daily,
Interval = 1,
FirstDayOfWeek = Microsoft.Graph.DayOfWeek.Sunday,
Index = WeekIndex.First
},
Range = new RecurrenceRange
{
Type = RecurrenceRangeType.Numbered,
StartDate = new Microsoft.Graph.Date(2020, 10, 6),
RecurrenceTimeZone = "Central Standard Time",
NumberOfOccurrences = 5
}
}
};
var graphClient = await MicrosoftAuthenticationProvider.GetGraphClient(CALENDAR_CLIENT_ID, CALENDAR_CLIENT_SECRET, CALENDAR_REDIRECT_URI, CALENDAR_ACCESS_SCOPES, CalendarRefreshToken)
.ConfigureAwait(false);
await graphClient.Me.Events[ExternalID]
.Request()
.UpdateAsync(tmpEvent)
.ConfigureAwait(false);
}
The bug is also repeatable by sending a PATCH using the graph explorer:
https://graph.microsoft.com/v1.0/me/events/{ID}
Update the event as "noEnd":
{"recurrence":{"pattern":{"type":"daily","interval":1,"month":0,"dayOfMonth":0,"firstDayOfWeek":"sunday","index":"first"},"range":{"type":"noEnd","startDate":"2020-10-06","endDate":"0001-01-01","recurrenceTimeZone":"Central Standard Time","numberOfOccurrences":0}}}
Update the event as "numbered":
{"recurrence":{"pattern":{"type":"daily","interval":1,"month":0,"dayOfMonth":0,"firstDayOfWeek":"sunday","index":"first"},"range":{"type":"numbered","startDate":"2020-10-06","endDate":"0001-01-01","recurrenceTimeZone":"Central Standard Time","numberOfOccurrences":5}}}
The following video displays the behavior the google attendee is experiencing:
https://www.screencast.com/t/uhwovvZf
Note: At the end of the video I show that switching the interval to 2 will cause the google event to be updated properly, so this is specifically a problem when the interval is 1.
Is this a known bug? Does anyone have a work-around for it?

Cannot refresh listview with observablecollection

I am trying to refresh my listview when an item is removed from it, but every time it gives me this error:
System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values.
Parameter name: index.
Before updating the ObservableCollection, I do this:
Groups = new ObservableCollection<RequestGroups>();
And then I fill it with this:
var temp = (JArray)resultJson["data"];
JArray jarr = temp;
foreach (JObject contents in jarr.Children<JObject>())
{
Requests obj = new Requests();
obj.Id = (int)contents["id"];
Client c = new Client();
c.address = contents["address"].ToString();
c.phone = contents["phone"].ToString();
c.name = contents["user"].ToString();
obj.Client = c;
obj.Date = contents["date"].ToString();
obj.Duration = contents["duration"].ToString();
obj.DurationText = "Duración: "+contents["duration"].ToString()+"h";
obj.Price = "$" + contents["price"].ToString();
String[] cDate = obj.Date.Split(' ');
String cHour = cDate[1]+" "+cDate[2];
obj.Hour = cHour;
String[] date = cDate[0].Split('-');
String title = months[date[1]] + " " + date[0];
obj.Title = title;
bool flag = false;
foreach(RequestGroups rqG in Groups){
if(rqG.Title.Equals(title)){
rqG.Add(obj);
flag = true;
}
}
if(!flag){
RequestGroups rq = new RequestGroups(title, date[1] + "-" + date[0]);
rq.Add(obj);
Device.BeginInvokeOnMainThread(() =>
{
Groups.Add(rq);
});
}
}
This is where I remove the items:
private async Task UpdateRequest(int status,int idEvent)
{
HttpClient hTTPClient = new HttpClient();
var client = new HttpClient();
client.Timeout = TimeSpan.FromSeconds(60);
client.BaseAddress = new Uri(Utils.baseUrl);
Dictionary<string, string> dataToSend = new Dictionary<string, string>();
dataToSend.Add("session", Utils.loginKey);
dataToSend.Add("eventId", idEvent+"");
dataToSend.Add("status", status.ToString());
string jsonData = Newtonsoft.Json.JsonConvert.SerializeObject(dataToSend, new KeyValuePairConverter());
var contentVar = new StringContent(jsonData, Encoding.UTF8, "application/json");
try
{
HttpResponseMessage response = await client.PostAsync("/UpdateEvent", contentVar);
var result = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
string contents = await response.Content.ReadAsStringAsync();
var resultJson = JObject.Parse(result);
if ((int)resultJson["status"] == 0)
{
await base.DisplayAlert((string)resultJson["msg"], "", "OK");
return;
}
else if ((int)resultJson["status"] == 1)
{
//I'm currently trying to reload the whole view, before this was calling the method above.
await this.mainPage.Navigation.PushAsync(new NavigationPage(new MasterMenu.MainPage()));
await getRequests();
}
else
{
await base.DisplayAlert("Error procesando la solicitud, intente más tarde", "", "Ok");
return;
}
}
}
catch (Exception ex)
{
Debug.WriteLine("Error update request: {0}", ex);
}
await Task.Delay(1);
}
If I leave it like that, UI will not update. Please help me, as I've been struggling with this issue for 2 days now. It happens exclusively on iOS.
The issue was fixed after updating iOS. The problem was caused because of a buggy iOS version that had problems indexing objects. After updating, everything ran as smoothly as usual. If anyone runs into this issue (exclusively on iOS), try updating both iOS and Xamarin Forms.

Resources