Make my own API capable of requesting from another API - c#

I have an existing and functioning API, which now have to be able to get data from another external API. How do i do that best?
I have tried with using HTTPClient, but i can't seem to get it to work. The error i get:
"No MediaTypeFormatter is available to read an object of type 'IList`1' from content with media type 'text/html'." -> I get this error on line 37. Can you spot it and/or tell me how I can do this differently, taking into account that all i want is the data (From the external API) and not to display it using a view, as this is an API?
Code below. I have also created a Pastebin: https://pastebin.com/MuKjEVys
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net;
namespace API.Controllers
{
[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/[controller]")]
[ApiController]
public class ExternalApiController : Controller
{
private string ExternalApiLink = "https://blablabla.com/api";
private string ExternalApiLinkGet = "/module/1/";
[HttpGet("getdata")]
public ActionResult<ExternalApi> GetDataFromExternal()
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(ExternalApiLink);
var requestApi = client.GetAsync(ExternalApiLinkGet);
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "XXXX");
requestApi.Wait();
var resultFromApi = requestApi.Result;
if (resultFromApi.IsSuccessStatusCode)
{
var readResponse = resultFromApi.Content.ReadAsAsync<IList<ExternalApi>>();
readResponse.Wait();
var data = readResponse.Result;
return Json(data);
}else
{
return NotFound();
}
}
}
}
}

Your response content seems to be json, while the content-type is text/html. If that is the case, the first thing to do would be to call the party that is exposing the service and have them fix it. In the meantime you could just read the content of the response as a string, and deserialize that string:
// Note that I made this method async.
public async Task<IActionResult> GetDataFromExternal()
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(ExternalApiLink);
// note that I moved this line above the GetAsync method.
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "XXXX");
// note that I'm disposing the response
using (var response = await client.GetAsync(ExternalApiLinkGet))
{
if (response.IsSuccessStatusCode)
{
// Since the response content is json, but the content-type
// is text/html, simply read the content as a string.
string content = await response.ReadAsStringAsync();
// You can return the actual received content like below,
// or you may deserialize the content before returning to make
// sure it is correct, using JsonConvert.DeserializeObject<List<ExternalApi>>()
// var data = JsonConvert.DeserializeObject<List<ExternalApi>>(content);
// return Json(data);
return Content(content, "application/json");
}
else
{
return NotFound();
}
}
}
}

Related

How to create correct post-request on C#?

I have a site on localhost created to learn how to send http requests, I send a post request to it, trying to simulate sending data via forms, as a response I expect that the data I sent will be added to the database, as it happens when sending via forms, but this does not happen. I assume that I am sending the post request incorrectly and something is missing in it
The site: localhost site
Post request: Pose request headers and data
My C# code:
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
namespace AirParsingScript
{
class Program
{
private static readonly HttpClient Client = new HttpClient();
static async Task Main()
{
var values = new Dictionary<string, string>
{
{ "Person.DocId_pre", "421" },
{ "Person.DocId", "ADGAGSA" },
{ "Person.Email", "4124421" },
{ "Person.TeleNumber", "4444" }
};
var content = new FormUrlEncodedContent(values);
var response = await Client.PostAsync("https://localhost:44391", content);
var responseString = await Client.GetStringAsync("https://localhost:44391");
// var responseString = await response.Content.ReadAsStringAsync();
Console.WriteLine(responseString);
}
}
}

error while testing the Echo Chat Bot on Azure

I'm following
https://towardsdatascience.com/creating-a-serverless-python-chatbot-api-in-microsoft-azure-from-scratch-in-9-easy-steps-2f1913fc9581
in creating a python chatbot, and my source code is as below, however when I try to run it, I'm getting an error. According to repositories that error is the adapter's on_error handler receives any exceptions thrown by bot's turn logic. If there is an exception thrown, the handler deletes the conversation state for the current conversation to prevent the bot from getting stuck in an error-loop caused by being in a bad state. any expert can help with this?
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Schema;
using System.Net;
using System;
using System.Net.Http;
using System.Text; // for class Encoding
using System.IO;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
namespace Microsoft.BotBuilderSamples.Bots
{
public class EchoBot : ActivityHandler
{
public class FlaskRequestModel
{
[JsonProperty("text")]
public string Text {get; set;}
}
protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
{
var replyText = $"{turnContext.Activity.Text}";
//if (!replyText.ToLower().Contains("Hey Bot")){ # Optional bit of code that only sends the sends the message to the back end if it contains a particular keyword
// return;
//}
var replyTextModel = new FlaskRequestModel()
{
Text = replyText
};
var jsonObject = JsonConvert.SerializeObject(replyTextModel);
var request = new HttpRequestMessage()
{
Content = new StringContent(jsonObject, Encoding.UTF8, "application/json"),
Method = HttpMethod.Post,
RequestUri = new Uri("yudao.azurewebsites.net"), // <- Replace the URL with the the URL for your function app
};
var httpClient = new HttpClient();
// httpClient.DefaultRequestHeaders.Add("API-Key","your API-key"); <- required if your HTTP trigger authorization was set to something other than Anonymous
var response = await httpClient.SendAsync(request, HttpCompletionOption.ResponseContentRead);
if (response.IsSuccessStatusCode)
{
var responseString = await response.Content.ReadAsStringAsync();
await turnContext.SendActivityAsync(MessageFactory.Text(responseString, responseString), cancellationToken);
}
else
{
await turnContext.SendActivityAsync(MessageFactory.Text("failure", "failure"), cancellationToken);
var responseString = await response.Content.ReadAsStringAsync();
await turnContext.SendActivityAsync(MessageFactory.Text(responseString, responseString), cancellationToken);
}
}
}
}
try this using regex:
A2 = "12 15|||Pform|||their|||REQUIRED|||-NONE-|||0"
intval=[val for val in A2.split('|||') if bool(re.search(pattern='\d+', string=val))]
Output:
['12 15', '0']

Create Work Item using Azure DevOps Rest API using C#

I am unable to create Work Item using Azure DevOps REST API as mentioned in Work Items - Create
Request:
https://dev.azure.com/{organization}/MyTestProject/_apis/wit/workitems/$Task?api-version=6.0-preview.3
Request Body:
[
{
"op": "add",
"path": "/fields/System.Title",
"value": "Task2"
}
]
Code to Get Response (Note this code works for all other POST Requests):
using (HttpResponseMessage response = client.SendAsync(requestMessage).Result)
{
response.EnsureSuccessStatusCode();
JsonResponse = await response.Content.ReadAsStringAsync();
}
Response: 400
Can someone please suggest?
It might be helpful to see your full example. However, here is a working example with Newtonsoft.Json (do not forget to create your PAT create personal access token):
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp2
{
class Program
{
static void Main(string[] args)
{
string PAT = "<personal access token>"; //https://learn.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops&tabs=preview-page
string requestUrl = "https://dev.azure.com/<my_org>/<my_project>/_apis/wit/workitems/$Task?api-version=5.0";
try
{
List<Object> flds = new List<Object>
{
new { op = "add", path = "/fields/System.Title", value = "Title" }
};
string json = JsonConvert.SerializeObject(flds);
HttpClientHandler _httpclienthndlr = new HttpClientHandler();
using (HttpClient client = new HttpClient(_httpclienthndlr))
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(
System.Text.ASCIIEncoding.ASCII.GetBytes(
string.Format("{0}:{1}", "", PAT))));
var request = new HttpRequestMessage(new HttpMethod("PATCH"), requestUrl)
{
Content = new StringContent(json, Encoding.UTF8, "application/json-patch+json")
};
HttpResponseMessage responseMessage = client.SendAsync(request).Result;
}
}
catch (Exception ex)
{
}
}
}
}
Additionally, you can consider to use .NET client libraries for Azure DevOps and TFS. Here is the example: Create a bug in Azure DevOps Services using .NET client libraries
application/json-patch+json is required.

How to get data from API request?

I'm pretty new to C# and this is my first time getting data from an api. I was wondering how do I get or call the data collected in this api request (MakeRequest). Preferably assign the data to a public string. The data from the api request is in json format.
using System;
using System.Net.Http.Headers;
using System.Text;
using System.Net.Http;
using System.Web;
namespace CSHttpClientSample
{
public partial class Form1 : Form
{
public async void MakeRequest()
{
var client = new HttpClient();
var queryString = HttpUtility.ParseQueryString(string.Empty);
// Request headers
client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", "{subscription key}");
// Request parameters
queryString["seasonId"] = "{string}";
var uri = "https://www.haloapi.com/stats/{title}/servicerecords/arena?players={players}&" + queryString;
var response = await client.GetAsync(uri);
}
}
}
So if the call succeeded, you should have your JSON string returned in the response variable you assign in the last line.
Use your debugger and inspect that variable. If you look at the MSDN doc for your GetAsync() method (Link), you can easily find out that the variable is of the type HttpResponseMessage. This class has an own page here telling you that there's a property Content.
This is your JSON string, now might come the part where you have to do some deserializing. Have fun.

Getting an UTF-8 response with httpclient in Windows Store apps

I'm building a Windows Store app, but I'm stuck at getting a UTF-8 response from an API.
This is the code:
using (HttpClient client = new HttpClient())
{
Uri url = new Uri(BaseUrl + "/me/lists");
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, url);
request.Headers.Add("Accept", "application/json");
HttpResponseMessage response = await client.SendRequestAsync(request);
response.EnsureSuccessStatusCode();
string responseString = await response.Content.ReadAsStringAsync();
response.Dispose();
}
The reponseString always contains strange characters which should be accents like é, and I tried using a stream, but the API I found in some examples don't exist in Windows RT.
Edit: improved code, still same problem.
Instead of using response.Content.ReadAsStringAsync() directly you could use response.Content.ReadAsBufferAsync() pointed by #Kiewic as follows:
var buffer = await response.Content.ReadAsBufferAsync();
var byteArray = buffer.ToArray();
var responseString = Encoding.UTF8.GetString(byteArray, 0, byteArray.Length);
This is working in my case and I guess that using UTF8 should solve most of the issues. Now go figure why there is no way to do this using ReadAsStringAsync :)
Solved it like this:
using (HttpClient client = new HttpClient())
{
using (HttpResponseMessage response = await client.GetAsync(url))
{
var byteArray = await response.Content.ReadAsByteArrayAsync();
var result = Encoding.UTF8.GetString(byteArray, 0, byteArray.Length);
return result;
}
}
I like El Marchewko's approach of using an extension, but the code did not work for me. This did:
using System.IO;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
namespace WannaSport.Data.Integration
{
public static class HttpContentExtension
{
public static async Task<string> ReadAsStringUTF8Async(this HttpContent content)
{
return await content.ReadAsStringAsync(Encoding.UTF8);
}
public static async Task<string> ReadAsStringAsync(this HttpContent content, Encoding encoding)
{
using (var reader = new StreamReader((await content.ReadAsStreamAsync()), encoding))
{
return reader.ReadToEnd();
}
}
}
}
Perhaps the problem is that the response is zipped. If the content type is gzip, you will need decompress the response in to a string. Some servers do this to save bandwidth which is normally fine. In .NET Core and probably .NET Framework, this will automatically unzip the response. But this does not work in UWP. This seems like a glaring bug in UWP to me.
string responseString = await response.Content.ReadAsStringAsync();
This thread gives a clear example of how to decompress the response:
Compression/Decompression string with C#
The HttpClient doesn't give you a lot of flexibility.
You can use a HttpWebRequest instead and get the raw bytes from the response using HttpWebResponse.GetResponseStream().
Can't comment yet, so I'll have to add my thoughts here.
You could try to use _client.GetStringAsync(url) as #cremor suggested, and set your authentication headers using the _client.DefaultRequestHeaders property.
Alternatively, you could also try to use the ReadAsByteArrayAsync method on the response.Content object and use System.Text.Encoding to decode that byte array to a UTF-8 string.
My approach using an Extension:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Web.Http;
namespace yourfancyNamespace
{
public static class IHttpContentExtension
{
public static async Task<string> ReadAsStringUTF8Async(this IHttpContent content)
{
return await content.ReadAsStringAsync(Encoding.UTF8);
}
public static async Task<string> ReadAsStringAsync(this IHttpContent content, Encoding encoding)
{
using (TextReader reader = new StreamReader((await content.ReadAsInputStreamAsync()).AsStreamForRead(), encoding))
{
return reader.ReadToEnd();
}
}
}
}

Categories

Resources