Using Moq to test HttpClient RequestClientCredentialsTokenAsync - c#

I am trying to mock an Http Client that uses the IdentityModel extension to request a client credentials token.
var tokenResponse = await _httpClient.RequestClientCredentialsTokenAsync(requestContent);
I started doing the setup with:
var httpClient = new Mock<HttpClient>();
var httpResponseMessage = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = JsonContent.Create(new
{
access_token = "token",
expires_in = 5000
})
};
var tokenResponse = ProtocolResponse.FromHttpResponseAsync<TokenResponse>(httpResponseMessage);
httpClient.Setup(x => x.RequestClientCredentialsTokenAsync(It.IsAny<ClientCredentialsTokenRequest>(), It.IsAny<CancellationToken>())).Returns(tokenResponse);
But i end up with:
System.NotSupportedException : Unsupported expression: x => x.RequestClientCredentialsTokenAsync(It.IsAny(), It.IsAny())
Extension methods (here: HttpClientTokenRequestExtensions.RequestClientCredentialsTokenAsync) may not be used in setup / verification expressions.
How can i mock the RequestClientCredentialsTokenAsync extension?

Looking at the internals of RequestClientCredentialsTokenAsync we can see that the base request it is using is SendAsync, so we need to mock SendAsync.
Extension call:
response = await client.SendAsync(request, cancellationToken).ConfigureAwait();
Final Setup:
var httpClient = new Mock<HttpClient>();
var httpResponseMessage = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = JsonContent.Create(new
{
access_token = "token",
expires_in = 5000
})
};
httpClient.Setup(x => x.SendAsync(It.IsAny<HttpRequestMessage>(), It.IsAny<CancellationToken>())).Returns(Task.FromResult(httpResponseMessage));
Result:

Related

Get Access token form OneLogin using the PKCE .net core API

I'm Trying to get the access token form OneLogin using the Authorization Code with PKCE. I'm able to go through step1 for PKCe and getting the authorization code back from OneLogin. But when i try to get the token using the authorization code sent by one login i keep getting 400 bad request error. I'm not sure what is wrong. I followed the info provided by oneLogin website to all required parameters in the request for Step 2. below the code i'm using. I will appreciate if some one can help on this.
public async Task GetAccessToken(string redirecturl, string authCode)
{
HttpClientHandler clientHandler = new HttpClientHandler();
clientHandler.ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => { return true; };
var client = new HttpClient(clientHandler);
var body = JsonConvert.SerializeObject(new
{
grant_type = "authorization_code",
code = authCode, ---The code returned from OneLogin in step 1
client_id=XXXXXXXXXXXXXXXXXX386d707215718",
redirect_uri=redirecturl,--The redirect URL registered in onelogin account
code_verifier=GetCacheEntry(CodeKey)-- the code verifier used in step one
});
var req = new HttpRequestMessage
{
Method = HttpMethod.Post,
RequestUri = new Uri("https://MySubdomain.onelogin.com/oidc/2/token"),
Content = new StringContent(body)
};
req.Content.Headers.ContentType= new MediaTypeHeaderValue(#"application/x-www-form-urlencoded");
var response = await client.SendAsync(req);
if (response.StatusCode == HttpStatusCode.OK)
{
var responseBody =await response.Content.ReadAsStringAsync();
var json = JsonConvert.DeserializeObject<OAuthTokenResponse>(responseBody);
memoryCache.Remove(CodeKey);
return Ok(json);
}
return BadRequest(response);
}
Looks like you're sending the body as a json content, although you've correctly specified the Content Type as x-www-form-urlencoded.
Here's how I create the body and send the request
var data = new Dictionary<string, string>(){
{ "code", code },
{ "code_verifier", AuthCodeParticipantDetail.CodeVerifier},
{ "grant_type", "authorization_code" },
{ "redirect_uri", AuthCodeParticipantDetail.CallBackUrl},
{"client_id", AuthCodeParticipantDetail.ClientId}
};
_httpClient.DefaultRequestHeaders.Accept.Clear();
_httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/x-www-form-urlencoded"));
HttpResponseMessage response = await _httpClient.PostAsync(url, new FormUrlEncodedContent(data));
var tokens = await response.Content.ReadFromJsonAsync<Tokens>();

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

Microsoft Graph Post action to Create group "Bad request"

We are trying to POST a request to the Microsoft Graph API to create a group, like explained HERE
The base url is: https://graph.microsoft.com/v1.0/groups
Content type is set to apllication/json
We have a valid Baerer token as well.
We are using the Group class from the Microsoft.Graph namespace (NuGet Package) so we populate the properties with our data and call the JsonConvert.SerializeObject(group) to serialize the group objecet to Json.
This is how we build up and serialze:
Microsoft.Graph.Group group = new Microsoft.Graph.Group();
group.Description = "Self help community for library";
group.DisplayName = "Library Assist";
group.GroupTypes = new[] { "Unified" };
group.MailEnabled = true;
group.MailNickname = "library";
group.SecurityEnabled = true;
string json = JsonConvert.SerializeObject(group);
var content = new StringContent(json);
var response = httpclient.PostAsJsonAsync(Uri, content).Result;
The headers of the HttpClient are set like this:
httpclient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "...value of baerer token...");
httpclient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
We are building the URL up starting from https://graph.microsoft.com/v1.0
adding /groups to it
In the response we are getting a Bad request status code 400.
This is implying that there is an error in the request URI, headers, or body but in the Graph Explorer the same code as above works fine, we get results in the response.
What am i overseeing?
Thank you for any feedback or suggestion.
Kind regards.
Since you already using the Microsoft.Graph namespace, you can use built-in the GraphServiceClient to make request as below. You needn't use the http client or serialize objects, this will be handled :
var graphserviceClient = new GraphServiceClient(
new DelegateAuthenticationProvider(
(requestMessage) =>
{
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", "<your-access-token>");
}));
var group = new Microsoft.Graph.Group
{
DisplayName = "Library Assist",
Description = "Self help community for library",
MailNickname = "library",
MailEnabled = true,
SecurityEnabled = true,
GroupTypes = new List<string> { "Unified" }
};
var createdGroup = await graphserviceClient.Groups.Request().AddAsync(group);
Reference - Intro to the Microsoft Graph .NET Client Library

Posting with C# httpclient with formencoded paramaters and headers

i am looking for a simple example using .net HttpClient to POST parameters and add headers. This is super easy in RestSharp but so far i cannot see a clear way how to do this with the HttpClient.
If you want to modify request headers for every request then the easiest way to do it is by setting the DefaultRequestHeaders properties. However, if you really want to change the request headers just for a particular request then you need to use the SendAsync method and pass it a HttpRequestMessage.
[Fact]
public async Task Post_a_form_and_change_some_headers()
{
var client = new HttpClient() { BaseAddress = _BaseAddress };
var values = new Dictionary<string, string>()
{
{"Id", "6"},
{"Name", "Skis"},
{"Price", "100"},
{"Category", "Sports"}
};
var content = new FormUrlEncodedContent(values);
var request = new HttpRequestMessage()
{
RequestUri = new Uri("devnull",UriKind.Relative),
Method = HttpMethod.Post,
Content = content
};
request.Headers.ExpectContinue = false;
request.Headers.Add("custom-header","a header value");
var response = await client.SendAsync(request);
response.EnsureSuccessStatusCode();
}

Adding Http Headers to HttpClient

I need to add http headers to the HttpClient before I send a request to a web service. How do I do that for an individual request (as opposed to on the HttpClient to all future requests)? I'm not sure if this is even possible.
var client = new HttpClient();
var task =
client.GetAsync("http://www.someURI.com")
.ContinueWith((taskwithmsg) =>
{
var response = taskwithmsg.Result;
var jsonTask = response.Content.ReadAsAsync<JsonObject>();
jsonTask.Wait();
var jsonObject = jsonTask.Result;
});
task.Wait();
Create a HttpRequestMessage, set the Method to GET, set your headers and then use SendAsync instead of GetAsync.
var client = new HttpClient();
var request = new HttpRequestMessage() {
RequestUri = new Uri("http://www.someURI.com"),
Method = HttpMethod.Get,
};
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("text/plain"));
var task = client.SendAsync(request)
.ContinueWith((taskwithmsg) =>
{
var response = taskwithmsg.Result;
var jsonTask = response.Content.ReadAsAsync<JsonObject>();
jsonTask.Wait();
var jsonObject = jsonTask.Result;
});
task.Wait();
When it can be the same header for all requests or you dispose the client after each request you can use the DefaultRequestHeaders.Add option:
client.DefaultRequestHeaders.Add("apikey","xxxxxxxxx");
To set custom headers ON A REQUEST, build a request with the custom header before passing it to httpclient to send to http server.
eg:
HttpClient client = HttpClients.custom().build();
HttpUriRequest request = RequestBuilder.get()
.setUri(someURL)
.setHeader(HttpHeaders.CONTENT_TYPE, "application/json")
.build();
client.execute(request);
Default header is SET ON HTTPCLIENT to send on every request to the server.

Categories

Resources