My website needs to post requests to a remote server to use its API.
I found a way in google by using HttpClient, just like this:
public async Task<string> HttpPostAsync(string uri, string url, List<KeyValuePair<string, string>> formData = null, string charset = "UTF-8", string mediaType = "application/x-www-form-urlencoded")
{
string tokenUri = url;
var client = new HttpClient();
client.BaseAddress = new Uri(uri);
HttpContent content = new FormUrlEncodedContent(formData);
content.Headers.ContentType = new MediaTypeHeaderValue(mediaType);
content.Headers.ContentType.CharSet = charset;
for (int i = 0; i < formData.Count; i++)
{
content.Headers.Add(formData[i].Key, formData[i].Value);
}
HttpResponseMessage resp = await client.PostAsync(tokenUri, content);
resp.EnsureSuccessStatusCode();
string token = await resp.Content.ReadAsStringAsync();
return token;
}
This way works, but the example is from 2017 when .NET Core 1.1 was just published.
Now .NET Core 3.0 is available and I wonder if there is any other better way to achieve this?
HttpClient is still the simplest/best way to directly make HTTP calls in .NET. For a method that always posts form content, you can simplify it a bit (no need to specify the media type, charset, etc. every time):
public static async Task<string> Post(string url, IEnumerable<KeyValuePair<string, string>> formData)
{
var client = new HttpClient();
var formContent = new FormUrlEncodedContent(formData);
var response = await client.PostAsync(url, formContent);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
var stringResponse = await Post("https://so57994582.free.beeceptor.com",
new Dictionary<string, string>() { { "hello", "world" } });
Related
This is the code i'm using
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", HttpContext.Session.GetString("JwtToken"));
var url = $"...some url";
var requestUri = new Uri(url);
var responseTask = client.GetAsync(requestUri);
responseTask.Wait();
var result = responseTask.Result;
if (result.IsSuccessStatusCode)
{
var reportResults = Task.Run(async() => await result.Content.ReadAsAsync<JArray>()).Result;
return reportResults;
}
}
Here if i try to access header like this
string error = responseTask.Headers.TryGetValue("X-TotalResults").FirstOrDefault();
I'm getting error
Task<HttpResponseMessage> does not contain a
definition for Headers and no accessible extension method Headers
So How i can read the header .. thanks in advance
You have a Task<HttpResponseMessage> rather than a HttpResponseMessage.
Instead of using .Result, which is dangerous for many reasons, convert your code to use async properly.
static HttpClient client = new HttpClient();
private async JArray GetReportResults()
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", HttpContext.Session.GetString("JwtToken"));
var url = $"...some url";
using (var response = await client.GetAsync(url))
{
result.EnsureSuccessStatusCode()
var reportResults = await result.Content.ReadAsAsync<JArray>();
return reportResults;
}
}
I would like to ask if it is possible for a created ASP.NET Web API (written in C#) to post to an external API?
If it is possible, please share sample code that can post to an url with adding headers and receive a callback from the external API.
A simple way to make HTTP-Request out of a .NET-Application is the System.Net.Http.HttpClient (MSDN). An example usage would look something like this:
// Should be a static readonly field/property, wich is only instanciated once
var client = new HttpClient();
var requestData = new Dictionary<string, string>
{
{ "field1", "Some data of the field" },
{ "field2", "Even more data" }
};
var request = new HttpRequestMessage() {
RequestUri = new Uri("https://domain.top/route"),
Method = HttpMethod.Post,
Content = new FormUrlEncodedContent(requestData)
};
request.Headers // Add or modify headers
var response = await client.SendAsync(request);
// To read the response as string
var responseString = await response.Content.ReadAsStringAsync();
// To read the response as json
var responseJson = await response.Content.ReadAsAsync<ResponseObject>();
Essentially you need use an instance of HttpClient to send an HttpRequestMessage to an endpoint.
Here is an example to post some jsonData to someEndPointUrl:
var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, someEndPointUrl);
request.Headers.Accept.Clear();
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
request.Content = new StringContent(jsonData, Encoding.UTF8, "application/json");
var response = await client.SendAsync(request, CancellationToken.None);
var str = await response.Content.ReadAsStringAsync();
if (response.StatusCode == HttpStatusCode.OK)
{
// handle your response
}
else
{
// or failed response ?
}
How do I pass request content in the HttpClient.GetAsync method? I need to fetch data depending upon request content.
[HttpGet]
public async Task<HttpResponseMessage> QuickSearch()
{
try
{
using (HttpClient client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Clear();
HttpResponseMessage response =await client.GetAsync("http://localhost:8080/document/quicksearch");
if (response.IsSuccessStatusCode)
{
Console.Write("Success");
}
If you are using .NET Core, the standard HttpClient can do this out-of-the-box. For example, to send a GET request with a JSON body:
HttpClient client = ...
...
var request = new HttpRequestMessage
{
Method = HttpMethod.Get,
RequestUri = new Uri("some url"),
Content = new StringContent("some json", Encoding.UTF8, ContentType.Json),
};
var response = await client.SendAsync(request).ConfigureAwait(false);
response.EnsureSuccessStatusCode();
var responseBody = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
If you want to send content, then you need to send it as query string (According to your API route)
HttpResponseMessage response =await client.GetAsync("http://localhost:8080/document/quicksearch/paramname=<dynamicName>¶mValue=<dynamicValue>");
And in API check for "paramName" and "paramValue"
this works for me:
using (var httpClient = new HttpClient())
{
var request = new HttpRequestMessage
{
Method = HttpMethod.Get,
RequestUri = new Uri("your url"),
Content = new StringContent("your json", Encoding.UTF8, ContentType.Json),
};
using (var response = await httpClient.SendAsync(request))
{
string apiResponse = await response.Content.ReadAsStringAsync();
}
}
EDITED:
This is minor different then #SonaliJain answer above:
MediaTypeNames.Application.Json instead of ContentType.Json
I'm assuming that your "request content" would be POST data, no?
If you're sending it using the standard form content way of doing it, you would first have to build the content:
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("username", "theperplexedone"),
new KeyValuePair<string, string>("password", "mypassword123"),
});
And then submit it using PostAsync instead:
var response = await client.PostAsync("http://localhost:8080/document/quicksearch", content);
Hi all thank you for your comments, i got the solution
[HttpGet]
public async Task<HttpResponseMessage> QuickSearch(HttpRequestMessage Query)
{
Debugger.Launch();
try
{
using (HttpClient client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Clear();
Console.WriteLine(Query);
HttpResponseMessage response = await client.GetAsync("http://localhost:8080/document/quicksearch/"+ Query.RequestUri.Query);
if (response.IsSuccessStatusCode)
{
Console.Write("Success");
}
else
{
Console.Write("Failure");
}
return response;
}
}
catch (Exception e)
{
throw e;
}
I have an endpoint in my ASP.NET Core 2.1 Controller
[HttpPost]
public async Task<bool> CheckStatus([FromBody] StatusModel model)
{
...code ommited
return true;
}
And I call this endpoint from other place in code like this:
await client.PostAsync('/CheckStatus', payloayd)
How can I retrive a bool value from this request?
Using Newtonsoft.Json, you can read the response of the request and parse it into a bool.
using Newtonsoft.Json;
public async Task<bool> GetBooleanAsync()
{
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var data = new { };
var url = "my site url";
var payload = new StringContent(JsonConvert.SerializeObject(data), Encoding.UTF8, "application/json");
var req = await client.PostAsync(url, payload);
var response = await req.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<bool>(response);
}
}
UPDATE
Looking back on this from a few years on, this can be simplified without the use of Newtonsoft.Json to read the response, by simply parsing the string data to a boolean.
public async Task<bool> GetBooleanAsync()
{
var data = new { };
var url = "my site url";
var payload = new StringContent(JsonConvert.SerializeObject(data), Encoding.UTF8, "application/json");
using var client = new HttpClient();
var response = await client.PostAsync(url, payload);
var data = await response.Content.ReadAsStringAsync();
return boolean.Parse(data);
}
However, if your boolean value is returned in a JSON object, then Newtonsoft.Json could be used to read that value.
Before Twitter switched to OAuth2, I was using the following query:
string atomTweetSearchURL = string.Format("http://search.twitter.com/search.atom?q={0}", searchText);
This no longer works, so now I'm trying to switch to OAuth2. I manage to successfully retrieve a token, but once I've got this, I seem to be unable to actually perform the search. Here's the latest incarnation of what I've tried:
var searchUrl = string.Format("https://api.twitter.com/1.1/search/tweets.json?q={0}&access_token={1}&token_type={2}", srchStr, twitAuthResponse.access_token, twitAuthResponse.token_type);
WebRequest srchRequest = WebRequest.Create(searchUrl);
using (var response2 = await srchRequest.GetResponseAsync())
{
Stream stream = response2.GetResponseStream();
using (StreamReader sr = new StreamReader(stream))
{
string jsonResponse = await sr.ReadToEndAsync();
}
}
This gives me a 400 - bad request.
I've also tried building the request like this:
System.Net.Http.HttpClient srchRequest = new System.Net.Http.HttpClient();
string authHdr = string.Format(srchHeaderFormat, twitAuthResponse.token_type, twitAuthResponse.access_token);
srchRequest.DefaultRequestHeaders.Add("Authorization", authHdr);
There's a massive quantity of articles out there detailing how to do this, but none of them seem to work correctly with WinRT. Can anyone point me in the right direction?
EDIT
Here's my code to get the token:
var oAuthConsumerKey = key;
var oAuthConsumerSecret = secret;
var oAuthUri = new Uri("https://api.twitter.com/oauth2/token");
var authHeaderFormat = "Basic {0}";
var authHeader = string.Format(authHeaderFormat,
Convert.ToBase64String(Encoding.UTF8.GetBytes(Uri.EscapeDataString(oAuthConsumerKey)
+ ":" +
Uri.EscapeDataString((oAuthConsumerSecret)))
));
var req = new HttpClient();
req.DefaultRequestHeaders.Add("Authorization", authHeader);
HttpRequestMessage msg = new HttpRequestMessage(new HttpMethod("POST"), oAuthUri);
msg.Content = new HttpStringContent("grant_type=client_credentials");
msg.Content.Headers.ContentType = new Windows.Web.Http.Headers.HttpMediaTypeHeaderValue("application/x-www-form-urlencoded");
HttpResponseMessage response = await req.SendRequestAsync(msg);
TwitAuthenticateResponse twitAuthResponse;
using (response)
{
string objectText = await response.Content.ReadAsStringAsync();
twitAuthResponse = JSonSerialiserHelper.Deserialize<TwitAuthenticateResponse>(objectText);
}
With the 1.1 API you don't pass the access token as part of the url, you need to include it as the Authorization header as "Bearer access_token" so you were almost there!
EDIT
To do this in the Windows.Web.Http namespace the following works:
private static async Task SearchTweets(AuthenticationResponse twitAuthResponse)
{
string srchStr = "tweet";
var client = new HttpClient();
var searchUrl = string.Format("https://api.twitter.com/1.1/search/tweets.json?q={0}", srchStr);
var uri = new Uri(searchUrl);
client.DefaultRequestHeaders.Authorization = new HttpCredentialsHeaderValue("Bearer", twitAuthResponse.AccessToken);
var response2 = await client.GetAsync(uri);
string content = await response2.Content.ReadAsStringAsync();
}
Or with System.Net.Http use the following:
This code will run the search for srchStr using the access token you already acquired as you showed in the first example:
var client = new HttpClient();
var searchUrl = string.Format("https://api.twitter.com/1.1/search/tweets.json?q={0}", srchStr);
var uri = new Uri(searchUrl);
client.DefaultRequestHeaders.Add("Authorization", string.Format("Bearer {0}", twitAuthResponse.access_token));
HttpResponseMessage response = await client.GetAsync(uri);
Task<string> content = response.Content.ReadAsStringAsync();
EDIT
This is a strange one, I tested your code and you're right it does throw an exception when attempting to add the Auth header, however the code I had used for grabbing the Access Token is almost identical but uses the System.Net.Http methods rather than the Windows.Web.Http ones that you use and it works, so I'll provide my code here, maybe this is a bug in the framework, or someone else can provide some more insight! This also uses the JSON.NET library which can be found on NuGet.
private static async Task SearchTweets(AuthenticationResponse twitAuthResponse)
{
string srchStr = "tweet";
var client = new HttpClient();
var searchUrl = string.Format("https://api.twitter.com/1.1/search/tweets.json?q={0}", srchStr);
var uri = new Uri(searchUrl);
client.DefaultRequestHeaders.Add("Authorization", string.Format("Bearer {0}", twitAuthResponse.AccessToken));
HttpResponseMessage response2 = await client.GetAsync(uri);
string content = await response2.Content.ReadAsStringAsync();
}
private async void GetAuthenticationToken()
{
var client = new HttpClient();
var uri = new Uri("https://api.twitter.com/oauth2/token");
var encodedConsumerKey = WebUtility.UrlEncode(TwitterConsumerKey);
var encodedConsumerSecret = WebUtility.UrlEncode(TwitterConsumerSecret);
var combinedKeys = String.Format("{0}:{1}", encodedConsumerKey, encodedConsumerSecret);
var utfBytes = System.Text.Encoding.UTF8.GetBytes(combinedKeys);
var encodedString = Convert.ToBase64String(utfBytes);
client.DefaultRequestHeaders.Add("Authorization", string.Format("Basic {0}", encodedString));
var data = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("grant_type", "client_credentials")
};
var postData = new FormUrlEncodedContent(data);
var response = await client.PostAsync(uri, postData);
AuthenticationResponse authenticationResponse;
using (response)
{
if (response.StatusCode != System.Net.HttpStatusCode.OK)
throw new Exception("Did not work!");
var content = await response.Content.ReadAsStringAsync();
authenticationResponse = JsonConvert.DeserializeObject<AuthenticationResponse>(content);
if (authenticationResponse.TokenType != "bearer")
throw new Exception("wrong result type");
}
await SearchTweets(authenticationResponse);
}
}
class AuthenticationResponse
{
[JsonProperty("token_type")]
public string TokenType { get; set; }
[JsonProperty("access_token")]
public string AccessToken { get; set; }
}