Post event to Outlook Calendar programmatically c# ASP.NET - c#

I'm integrating Outlook Calendar with a custom calendar with client credential flow and I'm trying to make my own api and not use MAPI all to much.
I would like to make a Post to https://outlook.office.com/api/v2.0/TenantDomain/users/useremail#domain/events
I am following this guide Create Events and have made the helper classes:
public class ToOutlookCalendar
{
[JsonProperty("Subject")]
public string Subject { get; set; }
[JsonProperty("Body")]
public Body Body { get; set; }
[JsonProperty("Start")]
public End Start { get; set; }
[JsonProperty("End")]
public End End { get; set; }
[JsonProperty("Attendees")]
public List<Attendee> Attendees { get; set; }
}
public class Attendee
{
[JsonProperty("EmailAddress")]
public EmailAddress EmailAddress { get; set; }
[JsonProperty("Type")]
public string Type { get; set; }
}
public class EmailAddress
{
[JsonProperty("Address")]
public string Address { get; set; }
[JsonProperty("Name")]
public string Name { get; set; }
}
public class Body
{
[JsonProperty("ContentType")]
public string ContentType { get; set; }
[JsonProperty("Content")]
public string Content { get; set; }
}
public class End
{
[JsonProperty("DateTime")]
public DateTimeOffset DateTime { get; set; }
[JsonProperty("TimeZone")]
public string TimeZone { get; set; }
}
my json object looks like this:
List<ToOutlookCalendar> toOutlook = new List<ToOutlookCalendar>();
toOutlook.Add(new ToOutlookCalendar
{
Start = new End
{
DateTime = DateTimeOffset.UtcNow,
TimeZone = "Pacific Standard Time"
},
End = new End
{
DateTime = DateTimeOffset.UtcNow,
TimeZone = "Pacific Standard Time"
},
Body = new Body
{
ContentType = "HTML",
Content = "testar for att se skit"
},
Subject = "testin",
Attendees = new List<Attendee>
{
new Attendee
{
EmailAddress = new EmailAddress
{
Address = "some email",
Name = "name"
}
},
new Attendee
{
EmailAddress = new EmailAddress
{
Address = "some email",
Name = "name"
}
}
}
});
return new JsonResult
{
Data = toOutlook,
ContentType = "application/json",
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
what i want to do is to make a PostAsync method like so:
var res = await ToOutlookKalendrar();
var stringPayload = await Task.Run(() => JsonConvert.SerializeObject(res));
var httpContent = new StringContent(stringPayload, Encoding.UTF8, "application/json");
var responsse = await client.PostAsync($"https://outlook.office.com/api/v2.0/{tenantDomain}/users/{userEmail}/events", stringPayload );
However this gives me 401 unauthorized, Have I missed something? do I need to include the accessToken in the Httpclient?
Update
I have added the token in the request headers but still get 401 unauthorized:
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + tokenn);
Update 2
I get this error now after having included the accessToken in the header:
reason="The access token is acquired using an authentication method that is too weak to allow access for this application. Presented auth strength was 1, required is 2.";error_category="invalid_token"
Now I'm lost, does the accesstoken need to be in the header or in the body of the json object?
Update 3
apperently I need to udate how i get the accessToken, I'll post the answer if I manage to do it right this time
Any help is appreciated!!

This question has been answered in another post, follow this link for the answer. I was using the the wrong requestURL here, everytnig is explained in the other post :)

Related

Updating Item in Sharepoint List with HttpClient through API fails with 403 FORBIDDEN (create and delete is working)

I try to do some CRUD operations on a sharepoint list, unfortunately I cannot update an item in the list. Since I can create and also delete items from the list, I think everything is fine with authentication and rights, but maybe I am not aware of some specific for the update process.
I have extracted the code from my libs to thrill it down to the most relevant lines, in an async method I first read the list and get the item to update
async Task Main()
{
var BaseUrl = "https://my_site/";
var credentials = new NetworkCredential("user", "pass", "domain");
string RequestDigest = null;
HttpClientHandler handler = new HttpClientHandler { Credentials = credentials };
var SpClient = new HttpClient(handler)
{
BaseAddress = new Uri(BaseUrl)
};
SpClient.DefaultRequestHeaders.Accept.Clear();
SpClient.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
var url = BaseUrl + $"_api/lists/getbytitle('Test')/items";
var response = await SpClient.GetAsync(url);
var data = await response.Content.ReadAsStringAsync();
if (response.StatusCode != HttpStatusCode.OK) throw new Exception(response.StatusCode.ToString() + " - " + response.RequestMessage.RequestUri);
SharepointListItems listEntries = JsonSerializer.Deserialize<SharepointListItems>(data);
var existing = listEntries.ListItems.FirstOrDefault(p => p.Title == "Eins");
This works fine, existing now contains the item from the list.
Now I tried to update this item:
// This will not work: StatusCode: 403, ReasonPhrase: 'FORBIDDEN', Version: 1.1, Content: System.Net.Http.HttpConnectionResponseContent, Headers:
existing.Title = "Changed";
string jsonString = JsonSerializer.Serialize<SharepointListItem>(existing);
So I tried to set up the sting for the item "by Hand" for testing purpose:
// This will also not work : StatusCode: 403, ReasonPhrase: 'FORBIDDEN', Version: 1.1, Content: System.Net.Http.HttpConnectionResponseContent, Headers:
// Prepare body string for testing
string jsonString = "{\"__metadata\": { \"type\": \"SP.Data.TestListItem\" }, \"Title\": \"Changed\"}";
Finally this is the code, that writes the item back to the list:
// write item back to list
if (RequestDigest == null || DateTime.Now > Convert.ToDateTime(RequestDigest.Split(',')[1]).AddSeconds(1800))
{
url = BaseUrl + "_api/contextinfo";
response = await SpClient.PostAsync(url, null);
data = response.Content.ReadAsStringAsync().Result;
var result = JsonSerializer.Deserialize<SharepointContext>(data);
RequestDigest = result.FormDigestValue;
SpClient.DefaultRequestHeaders.Remove("X-RequestDigest");
SpClient.DefaultRequestHeaders.Add("X-RequestDigest", RequestDigest);
SpClient.DefaultRequestHeaders.Add("X-HTTP-Method", "MERGE");
SpClient.DefaultRequestHeaders.Add("Accept", "application/json;odata=verbose");
}
if (existing.odataetag != null)
{
SpClient.DefaultRequestHeaders.Remove("If-Match");
SpClient.DefaultRequestHeaders.Add("If-Match", $"*");
}
var content = new StringContent(jsonString);
content.Headers.Clear();
content.Headers.Add("Content-Type", "application/json");
content.Headers.Add("X-RequestDigest", RequestDigest);
content.Headers.Add("X-HTTP-Method", "MERGE");
url = BaseUrl + $#"_api/lists/getbytitle('Test')/items({existing.Id})";
response = await SpClient.PostAsync(url, content);
Console.WriteLine(response.StatusCode);
response.Dump();
}
This sample I have extracted from my code and written in LinqPad. Here are the classes required for the full sample to run:
public class SharepointListItems
{
[JsonPropertyName("odata.metadata")]
public string odatametadata { get; set; }
[JsonPropertyName("value")]
public List<SharepointListItem> ListItems { get; set; }
}
public class SharepointListItem
{
public SharepointListItem() { }
[JsonPropertyName("odata.type")]
public string odatatype { get; set; }
[JsonPropertyName("odata.id")]
public string odataid { get; set; }
[JsonPropertyName("odata.etag")]
public string odataetag { get; set; }
[JsonPropertyName("odata.editLink")]
public string odataeditLink { get; set; }
public string Title { get; set; }
public int Id { get; set; }
}
public class SharepointContext
{
public string odatametadata { get; set; }
public int FormDigestTimeoutSeconds { get; set; }
public string FormDigestValue { get; set; }
public string LibraryVersion { get; set; }
public string SiteFullUrl { get; set; }
public string[] SupportedSchemaVersions { get; set; }
public string WebFullUrl { get; set; }
}
May anyone give any tips what I am doing wrong here?
As stated above the code runs fine on creating a new item. The only difference is that the body in this case only contains the item as Json without metadata and the etag header is not set.
Thank's for any hint.

Customize returning JSON from ASP.NET Core API , Values with Statuscode

I'm trying to return back JSON with customization , anyone can help to return the result like this :
{
status: 200,
message: "success",
data: {
var1: {
},
var2: {
}
}
}
with this code :
return Ok(new
{
var1,
var2
});
Why do you need to use the OkResult object?
A simple way of returning what you'd like is to use dynamic objets, or a class with properties matching the Json you'd like to get, and a JsonResult object.
dynamic json = new ExpandoObject();
json.Result = 200;
json.Message = "success";
json.Data.var1 = "whatever";
json.Data.var2 = "something else";
Response.StatusCode = json.Result; //matches the HTTP Status Code with the one from your json
return new JsonResult(json);
I used this for taking profile information from google id token , and then generate JWT token from my backend server and retuen back JWT and Profile info for client apps so this is the solution :
var profile = (new RetrnedUserProfile
{
Email = payload.Email,
FirstName = payload.GivenName,
FamilyName = payload.FamilyName,
PictureUrl = payload.Picture
});
return Ok(new ResponseModel
{
StatusCode = HttpStatusCode.OK,
Message = "success",
Data = new
{
profile,
accessToken
}
});
public class RetrnedUserProfile
{
public string FirstName { get; set; }
public string FamilyName { get; set; }
public string Email { get; set; }
public string PictureUrl { get; set; }
}
public class ResponseModel
{
public HttpStatusCode StatusCode { get; set; }
public string Message { get; set; }
public object Data { get; set; }
}

RestSharp doesn't get data or content of response

I have a route in my web service that receives POST request with Json body and returns simple array in Json format. I'm using PostMan for testing route and it works perfectly. but when I'm using RestSharp it doesn't get any content (or data in deserialization case).
Here is my C# code :
public static async Task<string> UpdateProfile(Profile user, string serviceUrl)
{
string bodyraw = JsonConvert.SerializeObject(user)
var client = new RestClient(serviceUrl);
var request = new RestRequest();
request.Method = Method.POST;
request.Parameters.Clear();
request.AddParameter("application/json", bodyraw, ParameterType.RequestBody);
request.OnBeforeDeserialization = resp => { resp.ContentType = "application/json"; };
var response = await client.ExecuteTaskAsync<Profile>(request);
return response.Data.Address;
}
And here is the Profile Class:
public class Profile
{
public string Name { get; set; }
public string Family { get; set; }
public string Email { get; set; }
public string Mobile { get; set; }
public string Address { get; set; }
public string Postal_code { get; set; }
public string Education { get; set; }
public string Gender { get; set; }
public string Age { get; set; }
public string Default_contact { get; set; }
public override string ToString()
{
return string.Concat(Name," " ,Family, " ", Address);
}
}
And this is PostMan OutPut:
{
"Name": "Holma",
"Family": "Kool",
"Email": "dr#gmail.com",
"Mobile": "09063094744",
"Address": "some city- basic av. sq 60",
"Postal_code": "10246666",
"Education": "1",
"Gender": "male",
"Age": "35"
}
And the PHP code that I used is:
function silverum_update_user_profile($request ){
$parameters = $request->get_json_params();// this is a WordPress method and works just fine
$name=sanitize_text_field($parameters['name']);
$family=sanitize_text_field($parameters['family']);
$email=sanitize_text_field($parameters['email']);
$mobile=sanitize_text_field($parameters['mobile']);
$address=sanitize_text_field($parameters['address']);
$postal_code=sanitize_text_field($parameters['postal_code']);
$education=sanitize_text_field($parameters['education']);
$gender=sanitize_text_field($parameters['gender']);
$age=sanitize_text_field($parameters['age']);
$extdp = [
"Name"=>$name,
"Family"=>$family,
"Email"=>$email,
"Mobile"=>$mobile,
"Address"=>$address,
"Postal_code"=>$postal_code,
"Education"=>$education,
"Gender"=>$gender,
"Age"=>$age
];
return $extdp;
}
When PHP method returns "Parameter" its OK and both PostMan and RestSharp can see output content but when method Returns new Array only PostMan is able to recive returnd object. I spent a couple of hour on the issue but didn't get anywhere. help please.
Try using the AddJsonBody() method within the RestRequest object as opposed to adding the parameter manually.
public static async Task<string> UpdateProfile(Profile user, string serviceUrl)
{
var client = new RestClient(serviceUrl);
var request = new RestRequest();
request.Method = Method.POST;
request.AddJsonBody(user);
request.OnBeforeDeserialization = resp => { resp.ContentType = "application/json"; };
var response = await client.ExecuteAsync<Profile>(request);
return response.Data.Address;
}

How do I serialize my class to send it as urlencoded with refit

Hi there I'm trying to send a POST method with refit, using postman so far I can say it's working, if I send the data with the x-www-form-encoded option, the json I send looks like this
{
"apt": "APT",
"apartment": "A103",
"author": "Someone",
"is_public": "True",
"is_complaint": "True",
"show_name": "True",
"title": "fhj",
"details": "vvkko"
}
I constructed my class in visual studio and my model to match it pasting that to json
namespace App.Models
{
public class ManyComplaints
{
public SingleComplaint data { get; set; }
}
public class SingleComplaint
{
public string apt { get; set; }
public string apartment { get; set; }
public string author { get; set; }
public string is_public { get; set; }
public string is_complaint { get; set; }
public string show_name { get; set; }
public string title { get; set; }
public string details { get; set; }
}
}
Here I'm not sure if I did right it's my api caller
[Headers("Content-Type: application/x-www-form-urlencoded")]
[Post("/api/complaints/")]
Task SubmitComplaint([Body(BodySerializationMethod.UrlEncoded)]SingleComplaint complaint);
And in this is the code that's sending the data
public async Task Post()
{
SingleComplaint data = new SingleComplaint
{
is_public = ShowPost,
is_complaint = Complaint,
show_name = ShowName,
author = Preferences.Get("UserName", null),
apt0 = Preferences.Get("Apt", null),
apartment = Preferences.Get("Apartment", null),
title = TitleEntry.Text,
details = DetailsEntry.Text
};
try
{
var myApi = RestService.For<IApiService>(Constants.webserver);
var serialized = JsonConvert.SerializeObject(data);
ManyComplaints complaint = await myApi.SubmitComplaint(data);
await DisplayAlert("Thanks", "Your message has been succesfully delivered", "Ok");
}
catch (Exception ex)
{
await Application.Current.MainPage.DisplayAlert("Error", ex.Message, "Ok");
}
}
Tried to use the line as string complaint = await myApi.SubmitComplaint(serialized); and also change that as string instead of the ManyComplaints class,
also tried to change the model as just the singlecomplaints but I couldn't get it to work, what I'm I missing or how do I make it work?
This answer might have come very late. But recently I was working on a similar use case. And the below code worked for me.
API Declaration (using Refit)
[Headers("Content-Type: application/x-www-form-urlencoded")]
[Get("")]
public HttpResponseMessage GetData([Body(BodySerializationMethod.UrlEncoded)] FormUrlEncodedContent content);
Calling the API
List<KeyValuePair<string, string>> contentKey = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("apt", "APT"),
new KeyValuePair<string, string>("apartment", "A103"),
new KeyValuePair<string, string>("author", "Someone")
};
FormUrlEncodedContent content = new FormUrlEncodedContent(contentKey);
HttpResponseMessage response = someClass.GetData(content);

Unsupported Media Type error when posting to Web API

Making a windows phone application and although I may easily pull from my Web Api I am having trouble posting to it. Whenever posting to the api I get the "Unsupported Media Type" error message and I'm not sure as to why it is happening considering the class I using as the base for my JSON post is the same as the one used in the api.
PostQuote (Post Method)
private async void PostQuote(object sender, RoutedEventArgs e)
{
Quotes postquote = new Quotes(){
QuoteId = currentcount,
QuoteText = Quote_Text.Text,
QuoteAuthor = Quote_Author.Text,
TopicId = 1019
};
string json = JsonConvert.SerializeObject(postquote);
if (Quote_Text.Text != "" && Quote_Author.Text != ""){
using (HttpClient hc = new HttpClient())
{
hc.BaseAddress = new Uri("http://rippahquotes.azurewebsites.net/api/QuotesApi");
hc.DefaultRequestHeaders.Accept.Clear();
hc.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await hc.PostAsync(hc.BaseAddress, new StringContent(json));
if (response.IsSuccessStatusCode)
{
Frame.Navigate(typeof(MainPage));
}
else
{
Quote_Text.Text = response.StatusCode.ToString();
//Returning Unsupported Media Type//
}
}
}
}
Quotes and Topic (Model)
public class Quotes
{
public int QuoteId { get; set; }
public int TopicId { get; set; }
public string QuoteText { get; set; }
public string QuoteAuthor { get; set; }
public Topic Topic { get; set; }
public string QuoteEffect { get; set; }
}
//Topic Model//
public class Topic
{
public int TopicId { get; set; }
public string TopicName { get; set; }
public string TopicDescription { get; set; }
public int TopicAmount { get; set; }
}
You should set the media type when creating StringContent
new StringContent(json, Encoding.UTF32, "application/json");
I found this question while working on a quick and dirty reverse proxy. I needed form data and not JSON.
This did the trick for me.
string formData = "Data=SomeQueryString&Foo=Bar";
var result = webClient.PostAsync("http://XXX/api/XXX",
new StringContent(formData, Encoding.UTF8, "application/x-www-form-urlencoded")).Result;
To fix the unsupported media type I had to use HttpRequestMessage and add header to accept json with MediaTypeWithQualityHeaderValue like bellow.
var httpRequestMessage = new HttpRequestMessage
{
Content = new StringContent(json, Encoding.UTF8, "application/json")
};
httpRequestMessage.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var httpResponse = await _client.PostAsync("/contacts", httpRequestMessage.Content);

Categories

Resources