How to POST to a specific URL using the Microsoft Graph Client - c#

I'm trying to send a POST request to the following URL using the MS Graph Client.
https://graph.microsoft.com/v1.0/sites/{SiteID}/lists/Documents/contentTypes/addCopyFromContentTypeHub
I looked at the various Request Builders and didn't see anything for "addCopyFromContentTypehub". There's a "ContentTypeAddCopyRequestBuilder", but that's a different action.
I tried getting access to the graph client's HttpProvider, but I can't figure out how to send the authentication with the request.
var requestUrl = graphServiceClient.Sites[siteId].Lists["Documents"].ContentTypes.AppendSegmentToRequestUrl("addCopyFromContentTypeHub");
var contentTypeId = "<ID>";
var body = $"{{\"contentTypeId\": \"{contentTypeId}\"}}";
using (var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, requestUrl))
{
httpRequestMessage.Content = new StringContent(requestUrl, Encoding.UTF8, "application/json");
//Errors here
var result = await graphServiceClient.HttpProvider.SendAsync(httpRequestMessage);
};
There error I get is:
"MsalUiRequiredException: No account or login hint was passed to the AcquireTokenSilent call."
My graph client uses an Azure AD App Registration to make all the calls so I need to include ".WithAppOnly()" on all my requests, but I don't see a way to do that using graphServiceClient.HttpProvider
Any help would be appreciated. Thanks!

You can authenticate HttpRequestMessage through Graph client
await graphServiceClient.AuthenticationProvider.AuthenticateRequestAsync(httpRequestMessage);
Code:
using (var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, requestUrl))
{
httpRequestMessage.Content = new StringContent(requestUrl, Encoding.UTF8, "application/json");
await graphServiceClient.AuthenticationProvider.AuthenticateRequestAsync(httpRequestMessage);
var result = await graphServiceClient.HttpProvider.SendAsync(httpRequestMessage);
};

Related

How to call a web api that has Oauth 2.0

Hi so we have an external web api we want to call to get data out. It is using oauth 2.0. Can somebody please explain how we would go about doing this in .NET either vb.net or c#. I have in the past created api, however this one seems very complicated. Firstly you have to be signed into their oauth web page they have which generates some cookies, using these cookies by syncing them up in postman we can see the data, however we need this to be within our .net app. Can somebody please help how we go about this. Some code would be useful.
Thanks
This is how usually OAuth 2 authentication works.
You basically log in with username and password (optional second factor) and then you receive a token, the so called Json Web Token or JWT (it holds encrypted information about your user, your access roles or groups you are member of as well as some timestamp which is the expiration time of the token).
In every subsequent request you make to the server, you pass this token in the request header (or in your case as cookie).
Example code:
Login request:
HttpRequestMessage httpRequest = new HttpRequestMessage(HttpMethod.Post, new Uri(_baseUrl, "token"));
string body = JsonConvert.SerializeObject(new
{
Username = _userName,
Password = _password,
secondFactor = secondFactor
});
httpRequest.Content = new StringContent(body, Encoding.UTF8, "application/json");
var response = await client.SendAsync(httpRequest);
var responseContent = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
TokenResult r = JsonConvert.DeserializeObject<TokenResult>(responseContent);
if (!string.IsNullOrWhiteSpace(r.token))
{
_token = r.token;
_tokenValidity = r.expirationDate;
_refreshToken = r.refreshToken;
_refreshTokenValidity = r.refreshTokenExpirationDate;
return _token;
}
else
{
throw new Exception($"Failed to get token from server.\r\n{responseContent}");
}
}
Now you use the _token in subsequent requests in the request header:
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", _token);
using HttpResponseMessage response = await client.GetAsync(new Uri(_baseUrl, relativePath));
if (response.IsSuccessStatusCode)
{
using var stream = await response.Content.ReadAsStreamAsync();
stream.Position = 0;
using var reader = new StreamReader(stream);
reader.ReadToEnd();
}
Please note, that usually the token has a certain lifetime after which it is basically useless. Some APIs offer a refresh token with which a new token can be requested without the user having to log in again with username and password, but that's beyond the scope of this question.
You said you have to use the token as cookie? Well there are APIs which work like this but personally I've never seen one like this, which is why I can't you help very much, but it shouldn't be much more than putting the token you got into a cookie with a certain name.
Hope this helps.
Not sure what you are asking. I have a controller code where I use web api call to authenticate user. You can use your own model to pass the data. If your web api expects token for request, then you might have to get the token first to give a call to any method. Hope this helps.
OktaUserDetailsModel Model = new OktaUserDetailsModel();
Model.username = model.UserName;
Model.password = model.Password;
using (var httpClient = new HttpClient())
{
HttpContent inputContent = new StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(Model), System.Text.Encoding.UTF8, "application/json");
HttpResponseMessage response = httpClient.PostAsync(ConfigurationManager.AppSettings["OktaAPIuri"], inputContent).Result;
if (response.IsSuccessStatusCode)
{
string strResponse = (new JavaScriptSerializer()).Deserialize<string>(response.Content.ReadAsStringAsync().Result);
if (strResponse.ToUpper() == "TRUE")
return OktaSingleSignOnLogin(astrReturnUrl, model.UserName);
else
return ErrorPage();
}
else
{
return ErrorPage();
}
}

Calling Get Request with Json Body using httpclient

I came with an issue this morning where the Api which I am calling is a Get Method but to get Get the Data from it I had to send the json body this is working good when I am testing it in the post man but I am not able to implement it in my project where I am calling this using HttpClient
here is the screenshot of post
It also have a bearer token which I pass in Authorization
Now when I am try to implement this at client side here is my code
var stringPayload = JsonConvert.SerializeObject(json);
var client = new HttpClient();
var request = new HttpRequestMessage
{
Method = HttpMethod.Get,
RequestUri = new Uri("https://myapiendpoint/serviceability/"),
Content = new StringContent(stringPayload, Encoding.UTF8, "application/json"),
};
var response = await client.SendAsync(request).ConfigureAwait(false);
response.EnsureSuccessStatusCode();
var responseBody = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
when I call this method using this code I get
System.Net.HttpStatusCode.MethodNotAllowed - Status code 405
I also tried changing this line
Method = HttpMethod.Get to Method = HttpMethod.Post
but still getting same error
I know this is bad implementation at API Side the request ideally should be POST but changing this is not in my hand and hence need to find the solution
almost search all over and trying all the variant of using GET Method finally the solution which worked for me in this case was this
var client = new HttpClient();
client.BaseAddress = new Uri("https://baseApi/");
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Add("Authorization", string.Format("Bearer {0}", token));
var query = new Dictionary<string, string>
{
["pickup_postcode"] = 400703,
["delivery_postcode"] = 421204,
["cod"] = "0",
["weight"] = 2,
};
var url = "methodurl";
var response = await client.GetAsync(QueryHelpers.AddQueryString(url, query));
var responseBody = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
return JsonConvert.DeserializeObject<MyModel>(responseBody);
Got QueryHelpers from Microsoft.AspNetCore.WebUtilities package

Proper way to send Raw XML to Tableau Rest API in C#

I simply want to send a rest request to Tableau's REST API but for some reason .NET isn't sending the raw XML (although tested and it works using Postman in chrome)
var admin = "\hardcoded_admin_user"\"";
var pass = "\hardcoded_pass"\"";
var tableau_signin = String.Format("<tsRequest> <credentials name={0} password={1}> </credentials> <site contentUrl=\"\"/> </tsRequest>", admin, pass);
//if user is validated make a REST call to Tableau Server
string endPoint = #"http://server/api/2.0/auth/signin";
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/xml"));
var post = client.PostAsync(endPoint,
new StringContent(tableau_signin)).Result;
}
Any help would be appreciated.
Provide Encoding and Content Type in the StringContent.
var post = client.PostAsync(endPoint,
new StringContent(tableau_signin, Encoding.UTF8, "application/xml")).Result;
var user = FormatTextBodyForUserSignIn(userName, password);
var httpContent = new StringContent(user, Encoding.UTF8, "application/xml");
var response = client.PostAsync($"api/{TableauAPIVersion}/auth/signin", httpContent).Result;

403 error when trying to get data from Reddit API

I am using oAuth to authenticate my app. I managed to get a code, access_token and refresh_token. So the next step would be trying to get info about the current user.
public async void GetCurrentUser()
{
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", AccessToken);
var response = await client.GetAsync("https://oauth.reddit.com/api/v1/me");
if (response.IsSuccessStatusCode)
{
var json = await response.Content.ReadAsStringAsync();
var obj = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(json);
}
}
}
This is the method I am using to do that. However the response is always an 403 (Forbidden) error code. Any idea what could be wrong? The access_token is what I got when I made a request to https://oauth.reddit.com/api/v1/access_token
I think the token is correct because when I create the same request with Fiddler it works.
ANSWER:
Fixed it by adding a custom user-agent
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, _endpointUri + "me");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", AccessToken);
request.Headers.Add("User-Agent", Uri.EscapeDataString("android:com.arnvanhoutte.redder:v1.2.3 (by /u/nerdiator)"));
var response = await client.SendAsync(request);

REST JSON GET - 400 Bad Request

I am working with the Basecamp API which is a REST (JSON) API using basic HTTP authentication over HTTPS.
This should be a GET request but when I run my code using GET I am receiving:
Cannot send a content-body with this verb-type
When I run it as a POST, I receive:
{"status":"400","error":"Bad Request"}
Does anyone know why this may be occurring?
using (var httpClient = new HttpClient()) {
string userName = "someone#someone.com";
string password = "somepassword";
var credentials = Convert.ToBase64String(Encoding.ASCII.GetBytes(string.Format("{0}:{1}", userName, password)));
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", credentials);
HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Post, "https://correctUrlHere);
requestMessage.Headers.Add("User-Agent", "TheProject (someone#someone.com)");
requestMessage.Content = new StringContent(string.Empty, Encoding.UTF8, "application/json");
var response = await httpClient.SendAsync(requestMessage);
var responseContent = await response.Content.ReadAsStringAsync();
Console.WriteLine(responseContent);
}
In this code I obviously swapped out the username, password, project name, and URL but in the actual code they are all correct.
GET requests must pass their parameters as url query and not as request body.
http://example.com?p1=1&p2=helloworld
If you don't have any content, as your example suggests, omit setting it on the request.
The BadRequest result indicates some error with your payload (again: content seems to be empty).

Categories

Resources