exception was thrown by the target of invocation” C# Httpclient - json.net

I have two API created in .net core 3.1 (let us say API A & API B) API A will call API B and merging two outputs. But when call,
I am getting:
Error:: Exception has been thrown by the target of an invocation.: Error Executing C# Script
The two APIs are running on different ports API A and API B.
I need to get the result from API A  to API B.so In my API A is a combination of API A and API B. I am using the same request for both.
The problem is when I call an external API call to API B from API B. But it works when I run API B only. I don't understand the issue
Code of the API B:
public async Task GetKeyData(string key){
string dataKey = string.Empty;
var requestUri = string.Format("{0}/{1}", _KeyUri, key);
HttpClient client = new HttpClient(new HttpClientHandler() {
UseDefaultCredentials = true
});
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var rawData = await client.GetAsync(requestUri);
// below line are getting error when i call from api A to this
var jsonResponse = await rawData.Content.ReadAsStringAsync(); //error showing here
string value = JsonConvert.DeserializeObject(jsonResponse);
//balance code
}
}
What mistake I am doing here?

Related

How to set resource URL for GraphServiceClient to fetch Groups?

I am trying to fetch AD groups from the Graph API using the groups:src1 endpoint value that I receive from _claims_sources in the JWT access token.
My client is using Client Credentials and can fetch info for all users and groups in the AD.
This is how I set it up:
private async Task<IList<Group>> GetUserGroupsAsync(string endpoint)
{
// Endpoint is from the claims in a previous OIDC request
// Setup a client if it does not exist
PrepareGraphApiClient();
// I can fetch my groups using the methods in the client
// var groupPage = await graphServiceClient.Me.MemberOf.Request().GetAsync();
// This is where I would like to use the resource URL received from the
// claims I receive in a previous OIDC request
var groupPageFromUrl = ???
...
}
private void PrepareGraphApiClient()
{
if (graphServiceClient != null) return;
try
{
AuthenticationContext authority = new AuthenticationContext(oidcOptions.Authority);
ClientCredential clientCredential = new ClientCredential(oidcOptions.ClientId, oidcOptions.ClientSecret);
var graphApiResource = "https://graph.microsoft.com";
AuthenticationResult authenticationResult = authority.AcquireTokenAsync(graphApiResource, clientCredential).Result;
graphServiceClient = new GraphServiceClient(new DelegateAuthenticationProvider(
async requestMessage =>
{
// Add token to outgoing requests
requestMessage.Headers.Authorization =
new AuthenticationHeaderValue("Bearer", authenticationResult.AccessToken);
}));
}
catch (Exception ex)
{
logger.LogDebug($"Could not create the graph client {ex}");
throw;
}
}
Can I use the resource URL from the claims with the GraphServiceClient or do I have to set up an HttpClient to make the request?
The endpoint identified in _claim_sources.src1 is for Azure AD Graph, so the token you use needs to be for the Azure AD Graph API (https://graph.windows.net), not for Microsoft Graph (https://graph.microsoft.com). That also means you can't use the Microsoft Graph SDK, as the API requests and responses are fundamentally different.
You have two options:
(Recommended) Use the fact that an endpoint is given only as an indication that you have to do the lookup, and make an equivalent call to Microsoft Graph using the Microsoft Graph SDK:
var memberOfIds = await graphServiceClient
.Users[userObjectId] # from the 'oid' in access token
.GetMemberObjects(securityEnabledOnly: true) # true if groupMembershipClaims is "SecurityGroup", false if it's "All"
.Request()
.PostAsync();
Use the endpoint given and build your own requests to Microsoft Graph using (for example) HttpClient. A quick'n'dirty example:
using (var client = new HttpClient())
{
# Always get the token right before you use it. ADAL will take care of getting a new one
# if needed, or using an existing cached token if not.
authenticationResult =
authority.AcquireTokenAsync("https://graph.windows.net", clientCredential)
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", authResult.AccessToken);
# Make the API request to Azure AD Graph. Note we have to include the api-version and
# the request body.
HttpResponseMessage response = await client.PostAsync(
$"{src}?api-version=1.6", new StringContent(
"{'securityEnabledOnly': true}", # true if groupMembershipClaims is "SecurityGroup", false if it's "All"
UnicodeEncoding.UTF8,
"application/json"));
if (response.IsSuccessStatusCode)
{
# Note we're deserializing as if it were a Microsoft Graph response to getMemberObjects,
# rather than an Azure AD Graph response. Though it works, this is somewhat risky, and
# it would be more correct to explicitly define the form of an Azure AD Graph response.
var memberOfIds = JsonConvert.DeserializeObject<DirectoryObjectGetMemberObjectsCollectionResponse>(
await response.Content.ReadAsStringAsync()).Value;
}
}
As a side note, I notice that you have the call to acquire a token outside of the DelegateAuthenticationProvider you've given to the Microsoft Graph library. You should put the AcquireTokenAsync call inside, so that it retrieves a fresh token for each and every Microsoft Graph request. The library (ADAL) will take care of using a cached token (if one is available), or making a new token request (if none are available or if those available are expired). Something like this:
graphServiceClient = new GraphServiceClient(new DelegateAuthenticationProvider(
async requestMessage =>
{
// Get fresh token
AuthenticationResult authenticationResult =
await authority.AcquireTokenAsync(graphApiResource, clientCredential);
// Add token to outgoing requests
requestMessage.Headers.Authorization =
new AuthenticationHeaderValue("Bearer", authenticationResult.AccessToken);
}));

Unable to call API's from ASP.NET MVC App?

I've created a API where I want to call another API from, for testing im using Pokemon API with PostMan. However when I want to call this API im my own API application getting an error. Code executed when API is getting called:
[System.Web.Http.AcceptVerbs("GET")]
[System.Web.Http.HttpGet]
[System.Web.Http.Route("RedirectApi")]
public async Task<object> getCall()
{
checkAuthorisation();
setVariables();
if (isAuthorized == true)
{
HttpClient client = new HttpClient();
HttpResponseMessage response = await client.GetAsync("https://pokeapi.co/api/v2/pokemon/ditto/");
var code = response.StatusCode;
response.EnsureSuccessStatusCode();
string responseBody = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject(responseBody);
}
else
{
return JsonConvert.DeserializeObject("Unauthorized");
}
}
Im calling my API with this link:
http://localhost:54857/GetPokemon
Whenever I execute this using Postman in debug mode it executes but fails on this code:
HttpResponseMessage response = await client.GetAsync("https:/pokeapi.co/api/v2/pokemon/ditto/");
It also does not give me any feedback except what Postman gives me back:
Hope someone can help!
Thanks in advance!

dotnet core webapi calling .net webapi2

I am calling a .NET WebApi2 endpoint from a dotnet core webapi. When I debug into the .NET WebApi2 POST endpoint, my value is always null. Is this not possible to do?
When I call the GET endpoint with an ID, the ID is passed with no issues.
I have used both Postman and Fiddler to debug. Whenever I pass my JSON object from Postman to the .NET WebApi2 POST endpoint, my value is populated.
Beyond frustrated as this seems pretty simple. :,(
Updated to include code
dotnet core web api (calling from Postman)
[HttpPost]
public async Task PostAsync([FromBody] string value)
{
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var jsonObject = new JObject();
jsonObject.Add("text", "Rich");
var response = await client.PostAsJsonAsync("http://localhost:54732/api/Rich", jsonObject);
var responseResult = response.Content.ReadAsStringAsync().Result;
}
.NET WebApi2 (JObject is always null)
// POST: api/Rich
public void Post(JObject value)
{
}
This boils down to using JObject basically. For your older Web Api action, JObject works merely because you're posting JSON, and JObject is a dynamic. However, that is an entirely incorrect approach. You should be binding to a concrete class that represents the JSON being posted. That said, you may or may not be able to change anything there, and its not technically the source of your current issue.
The actual source is that you're attempting to send a JObject, which is not doing what you think it is. Again, JObject is a dynamic. It has accessors to parse and access the underlying JSON, but it does not actually expose the members of that JSON object directly. As a result, if you attempt to serialize it, you won't get anything usable from it. Passing it to PostAsJsonAsync causes it to be serialized.
What you actually need is something like:
var jsonObject = new { text = "Rich" };
Then, what you're passing to PostAsJsonAsync will be an anonymous object with actual members that can be serialized.
My "REAL" issue turned out to be Transfer-Encoding: chunked was being sent in the request header.
Here is my corrected code (dotnet core web api):
public async Task PostAsync([FromBody] JObject value)
{
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new
MediaTypeWithQualityHeaderValue("application/json"));
var jsonObject = new { variable1 = "Rich" };
var json = JsonConvert.SerializeObject(jsonObject);
var content = new StringContent(json, Encoding.UTF8, "application/json");
content.Headers.ContentLength = json.Length;
var response = await client.PostAsync("http://localhost:54732/api/Rich", content);
var responseResult = response.Content.ReadAsStringAsync().Result;
}
Here is my .NET WebApi2 code:
public IHttpActionResult Post([FromBody]RichTest value)
{
return Ok(value.variable1 + " done");
}
public class RichTest
{
public string variable1 { get; set; }
}
When I set the content.Headers.ContentLength, the Transfer-Encoding: chunked is removed. Now my code is working!!
I am still curious why the original PostAsJsonAsync does not work...

IdentityServer Hybrid Flow - Access Token is null after user successful login

I'm having problems in retrieving access token of an authenticated user. below is my configuration
ASP.NET MVC 5 Client:
OpenIdConnect
IdentityServer3 libraries
ResponseType = "code id_token"
ASP.NET Core Identity Server:
IdentityServer4 libraries
Client Config: AllowedGrantTypes =
GrantTypes.HybridAndClientCredentials,
I'm trying to get the access token in my client using this:
AuthorizationCodeReceived = async n =>
{
// use the code to get the access and refresh token
var tokenClient = new TokenClient(TokenEndpoint, "clientid", "secret");
var response = await tokenClient.RequestAuthorizationCodeAsync(n.Code, n.RedirectUri);
},
I used this reference for above implementation - https://github.com/IdentityServer/IdentityServer3/issues/2457
but the properties in the response has null values. I need the access token so that the user logged in the client can access the api. Below is another way that i'm trying to retrieve the access token:
public async Task<ActionResult> CallApiUsingUserAccessToken()
{
var user = User as ClaimsPrincipal;
var accessToken = user.FindFirst("access_token").Value;
var client = new HttpClient();
client.SetBearerToken(accessToken);
var content = await client.GetStringAsync("http://localhost:6001/api/values");
ViewBag.Json = JArray.Parse(content).ToString();
return View("json");
}
however, user.FindFirst("access_token").Value; is null. I'm thinking of migrating my MVC client to Core because I've tried the IdentityServer4 version in an asp.net core but that seems to be a big migration to my part. Thank you.
[updated]
It never occured to me that the endpoints in the IdentityServer3 differs from IDS4. I did have to change var tokenClient = new TokenClient(TokenEndpoint, "client", "secret"); to var tokenClient = new TokenClient("http://localhost:9000/connect/token", "client", "secret") since TokenEndpoint in IDS3 is http://localhost:9000/core/connect/token which the endpoint "core" does not exist in IDS4. I'm able to get the access token in this line var tokenResponse = await tokenClient.RequestAuthorizationCodeAsync(n.Code, n.RedirectUri); but after authorization, i'm still getting nullreference exception to this var accessToken = user.FindFirst("access_token").Value; line of code.
Given the IdentityServer 4 documentation on
Switching to Hybrid Flow and adding API Access back
and an example client from IdentityServer3.Samples
MVC OWIN Client (Hybrid)
you should be able to setup a working environment.
To support debugging you should always do proper response handling as shown in example below and copied from example client. Add any response errors to your question.
Notifications = new OpenIdConnectAuthenticationNotifications
{
AuthorizationCodeReceived = async n =>
{
// use the code to get the access and refresh token
var tokenClient = new TokenClient(
Constants.TokenEndpoint,
"mvc.owin.hybrid",
"secret");
var tokenResponse = await tokenClient.RequestAuthorizationCodeAsync(
n.Code, n.RedirectUri);
if (tokenResponse.IsError)
{
throw new Exception(tokenResponse.Error);
}
Finally I recommend to add code for all important parts of an IdentityServer3/4 based setup - because the truth is usually burried in the details.
According to these posts, https://github.com/IdentityServer/IdentityServer3/issues/2457 & https://github.com/IdentityServer/IdentityServer3/issues/2015#issuecomment-172623173, it is a good practice to not include the access token in the claims. Hence, I followed his example, https://github.com/Mich-b/IdentityServerTMLClient/blob/master/IdentityServerTMLClient/Startup.cs, in which the access token is added in the Http Session storage.

Issue with httpclient.getstringasync

I want to develop a Dragon Timer Windows Store App for GuildWars 2.
Whatever, I save a timestamp in a sql database. To get this timestamp in the app, I made a php script that writes the content of the database to a page. Now I'm trying to receive that string via the HttpClient.GetStringAsync() Method. Here's the code snipped:
async Task<Dictionary<String, DateTime>> GetKillTimes()
{
Dictionary<String, DateTime> killTimes = new Dictionary<String,DateTime>();
HttpClient httpClient = new HttpClient();
Task<string> getStringTask = httpClient.GetStringAsync("http://www.wp10454523.server-he.de/truhentimer/getTimes.php");
String rawKillTimes = await getStringTask;
//Parse to Dictionary...
return killTimes;
}
I tried some different Methods I got from google (WebRequest ...), but every one got stuck at the Get-Part. Am I maybe misinterpreting the function? Shouldn't I get the content of the page, which is a simple String?
You have to use await keyword as web request & response in WinRT are asynchronous so you have to use await keyword. await before httpClient.GetStringAsync(...)
Task<string> getStringTask = await httpClient.GetStringAsync("http://www.wp10454523.server-he.de/truhentimer/getTimes.php");

Resources