Before I start, I would like to say that I have googled solutions to this problem but have either not understood them (I am a newbie) or they do not work.
What I want to do is send JSON data to a REST API on localhost:8000, in this format:
{
"username" : "myusername",
"password" : "mypass"
}
Then, I expect a response which holds a string token, like the following,
{
"token" : "rgh2ghgdsfds"
}
How do send the json data and then parse the token from the response?
I have seen synchronous methods of doing this but for some reason, they do not work (or simply because I do not know what namespace it is in). If you apply an async way of doing this, could you please explain to me how it works?
Thanks in advance.
I use HttpClient. A simple example:
var client = new HttpClient();
client.BaseAddress = new Uri("localhost:8080");
string jsonData = #"{""username"" : ""myusername"", ""password"" : ""mypassword""}"
var content = new StringContent (jsonData, Encoding.UTF8, "application/json");
HttpResponseMessage response = await client.PostAsync("/foo/login", content);
// this result string should be something like: "{"token":"rgh2ghgdsfds"}"
var result = await response.Content.ReadAsStringAsync();
Where "/foo/login" will need to point to your HTTP resource. For example, if you have an AccountController with a Login method, then instead of "/foo/login" you would use something like "/Account/Login".
In general though, to handle the serializing and deserializing, I recommend using a tool like Json.Net.
As for the question about how it works, there is a lot going on here. If you have questions about how the async/await stuff works then I suggest you read Asynchronous Programming with Async and Await on MSDN
This should be fairly easy with HttpClient.
Something like this could work. However, you might need to proxy data from the device/simulator somehow to reach your server.
var client = new HttpClient();
var content = new StringContent(
JsonConvert.SerializeObject(new { username = "myusername", password = "mypass" }));
var result = await client.PostAsync("localhost:8080", content).ConfigureAwait(false);
if (result.IsSuccessStatusCode)
{
var tokenJson = await result.Content.ReadAsStringAsync();
}
This code would probably go into a method with the following signature:
private async Task<string> Login(string username, string password)
{
// code
}
Watch out using void instead of Task as return type. If you do that and any exception is thrown inside of the method that exception will not bubble out and it will go unhandled; that will cause the app to blow up. Best practice is only to use void when we are inside an event or similar. In those cases make sure to handle all possible exceptions properly.
Also the example above uses HttpClient from System.Net.HttpClient. Some PCL profiles does not include that. In those cases you need to add Microsoft's HttpClient library from Nuget. I also use JSON.Net (Newtonsoft.Json) to serialize the object with username and password.
I would also note that sending username and password in cleartext like this is not really recommended and should be done otherwise.
EDIT: If you are using .NET Standard on most of the versions you won't need to install System.Net.HttpClient from NuGet anymore, since it already comes with it.
try this code.
HttpClient httpClient = new HttpClient();
httpClient.BaseAddress = new Uri(APIAddress); // Insert your API URL Address here.
string serializedObject = JsonConvert.SerializeObject(data);
HttpContent contentPost = new StringContent(serializedObject, Encoding.UTF8, "application/json");
try
{
HttpResponseMessage response = await httpClient.PostAsync(ControllerWithMethod, contentPost);
return response;
}
catch (TaskCanceledException ex)
{
throw;
}
catch (Exception ex)
{
return new HttpResponseMessage();
}
Related
I want to download data of this website into a json file but as I am quite new to coding with C# I cant manage to get the data. I want to get Data of https://discosweb.esoc.esa.int/api/objects the authorization via token works but I dont know how I can send a request so the server gives me a json back and I cant find a solution online. I cant give you a screenshot of the API because you have to be logged in to see it. Plz ask me for detailed information if you can help me. Thank you realy for trying.
The code I want to run is here.
class Program
{
static HttpClient client = new HttpClient();
static void Main(string[] args)
{
client.BaseAddress = new Uri("https://discosweb.esoc.esa.int");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/vnd.api+json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("my_token");
var httpRequest = (HttpWebRequest)WebRequest.Create(client.BaseAddress);
var httpResponse = (HttpWebResponse)httpRequest.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var streamReaderResult = streamReader.ReadToEnd();
}
Console.WriteLine("Status https://discosweb.esoc.esa.int : " + httpResponse.StatusCode);
}
}
Try this
var url = "https://discosweb.esoc.esa.int/api/objects";
var httpRequest = (HttpWebRequest)WebRequest.Create(url);
httpRequest.Method = "POST";
httpRequest.Headers["Authorization"] = "Basic XXXx";
httpRequest.ContentType = "";
httpRequest.Headers["Content-Length"] = "0";
var httpResponse = (HttpWebResponse)httpRequest.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Console.WriteLine(httpResponse.StatusCode);
Where XXXx is user:password in base64.
Here is a basic implementation for making that API call to get the JSON result. You will need to parse that JSON into something other than a string but I'll assume you can handle that part.
This uses System.Net.HttpClient which is the modern HTTP api provided by .NET. Its operations are async so hopefully your code is or can be written to properly await async operations.
//Someplace convenient, create a shared HttpClient to avoid
//creating and disposing for each request.
HttpClient client = new HttpClient();
string data = await GetObjects(client);
//Example implementation
public async Task<string> GetObjects(HttpClient client)
{
string url = "https://discosweb.esoc.esa.int/api/objects";
using (HttpRequestMessage msg = new HttpRequestMessage(HttpMethod.Get, url))
{
msg.Headers.Authorization =
new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", "your personal access token here");
using (var result = await client.SendAsync(msg))
{
string content = await result.Content.ReadAsStringAsync();
return content;
}
}
}
While I may be a month late, I've actually developed an SDK for this particular API.
So, if you use this SDK it's pretty simple to do what you want. You can essentially forget about handling anything HTTP related, my SDK abstracts all of that away.
For example, to fetch Sputnik's data (which has an ID of 1) you'd run.
HttpClient innerClient = new();
innerClient.BaseAddress = "https://discosweb.esoc.esa.int/api/"
innerClient.DefaultRequestHeaders.Authorization = new("bearer", yourApiKey);
DiscosClient client = new();
DiscosObject sputnik = await client.GetSingle<DiscosObject>("1");
If you're using ASP.NET, there's a set of DI extensions that can actually set it all up for you, so you can skip the first three lines.
If you do choose to use it, please let me know, as it would be nice knowing my SDK is getting some use. If you have any issues, please just reach out through the GitHub issues page and I'll try to help!
Someone's probably done this before but I can't seem to formulate the question properly to find results. I want to make AJAX calls from a view, but I can't directly call the external API from javascript because there's a key that I can't expose. My idea is to have another controller action that I call from the page that calls the actual external REST API I want to get data from and just passes it on as a JSON. I see lots of examples of getting a JSON through C# and deserializing it but not many where you get a JSON and then return it and consume it from the view. Any help appreciated.
public JsonResult GetStuff()
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri(URL);
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = client.GetAsync("Stuff/?Id=" + id).Result;
*code to take response and pass it on as a JSON that I can consume from Javascript
}
Here is what I recommend.
[HttpGet("myapi/{id}");
public async Task MyApi(int id) {
// Replace these lines as needed to make your API call properly.
using HttpClient client = new() {
BaseAddress = REMOTE_SERVER_BASE
}
// Make sure to properly encode url parameters if needed
using HttpResponseMessage response = await client.GetAsync($"myapi/{id}");
this.HttpContext.Response.StatusCode = (int)response.StatusCode;
foreach (KeyValuePair<string, IEnumerable<string>> header in response.Headers) {
this.HttpContext.Response.Headers[header.Key] = new StringValues(header.Value.ToArray());
}
await response.Content.CopyToAsync(this.HttpContext.Response.Body);
}
This will copy all the common response fields such as status code, headers, and body content, over to your response.
This code isn't tested so you might have to tweak it a bit but it should be enough to get you started.
Due to the fact that I need to convert this C# dll into a tlp file to be called from Visual Basic 6, I need avoid using external dependencies. I have used RestSharp to consume a WebAPI by doing the following (working):
using RestSharp;
using Newtonsoft.Json;
..
public string GetToken (string Key, string Password) {
var client = new RestClient (BaseUrl + "auth/GetToken");
var request = new RestRequest (Method.POST);
request.AddHeader ("cache-control", "no-cache");
request.AddHeader ("Content-Type", "application/json");
Dictionary<string, string> data = new Dictionary<string, string> {
{ "APIKey", Key },
{ "APIPassword", Password }
};
var dataJSON = JsonConvert.SerializeObject (data);
request.AddParameter ("undefined", dataJSON, ParameterType.RequestBody);
IRestResponse response = client.Execute (request);
GetTokenResults g = JsonConvert.DeserializeObject<GetTokenResults> (response.Content);
return g.Token;
}
where GetTokenResults was a struct that contained a declaration for the string Token. I want to achieve this same functionality without using RestSharp. Here is my unsuccessful attempt:
using System.Net.Http;
using System.Net.Http.Headers;
..
public async void GetToken (string Key, string Password) {
var client = new HttpClient ( );
client.DefaultRequestHeaders.Accept.Clear ( );
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue ("application/json"));
client.BaseAddress = new Uri (BaseUrl + "auth/GetToken");
Dictionary<string, string> data = new Dictionary<string, string> {
{ "APIKey", Key },
{ "APIPassword", Password }
};
var dataJSON = JsonConvert.SerializeObject (data);
var content = new StringContent (dataJSON, Encoding.UTF8, "application/json");
var response = await client.PostAsync ("", content);
}
I am unclear on how to achieve the same results (send API key and password, return token as string) using HttpClient as I did using RestSharp earlier. Anything that can point me in the right direction is greatly appreciated!
I think you got stung by this issue. In short, the URI in client.BaseAddress needs a slash at the end of it.
However, I wouldn't simply add it, I'd consider doing it a little different. Presumably your BaseUrl already has a trailing slash, given you're appending "auth/GetToken" to it. I'd do it this way:
client.BaseAddress = new Uri(BaseUrl);
...
var response = await client.PostAsync("auth/GetToken", content);
As you can see, HttpClient fits very cleanly with how your code is already set up, i.e. you have a "base" address with a trailing slash and you want to append to it for a specific call.
That should get you un-stuck to this point. The next thing you'll need to tackle is deserializing the JSON response so you can get the token out of it. It's similar to how you did it in RestSharp, except that response.Content is not a string in the HttpClient world, so you need one more step to get that:
var json = await response.Content.ReadAsStringAsync();
GetTokenResults g = JsonConvert.DeserializeObject<GetTokenResults>(json);
return g.Token;
Last thing you'll need to do to get this to compile is change the method signature to:
public async Task<string> GetTokenAsync
One final note: you are now in the async world, and that's a good thing, but you need to know how to use it correctly or you could end up with deadlocks and other mysterious bugs. In short, don't block on async code by calling .Result or .Wait() anywhere up the call stack. That's by far most common mistake people make. Use async/await all the way down.
I think you are missing first parameter in the method PostAsync i.e. requestUri=Client.BaseAddress (see my implementation below).
Try with this first, if did not work, read below. I have a little different implementation where I passed client.BaseAddress as first parameter and I am passing my content as ByteArrayContent. In my case I have to pass my content as "application/x-www-form-urlencoded" excerpt of my code:
var buffer = Encoding.UTF8.GetBytes(content);
var byteContent = new ByteArrayContent(buffer);
//as I can't send JSON, probably, you can skip as it's already JSON
byteContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/x-www-form-urlencoded");
//requestUri=client.BaseAddress
await client.PostAsync(requestUri, byteContent).ConfigureAwait(false);
We have somewhat different need but I think you are pretty close. If it does not help, write me I will share my code. After reading the comment, I would like to share how I have made my HttpClient. The code is as it is:
using (var client = CreateMailClientForPOST($"{BaseUrl}/"))
{
//removed code, you can call above code as method like
var response= await client.DoThingAsAsync($"{client.BaseAddress}, content").ConfigureAwait(false);
}
protected HttpClient CreateMailClientForPOST(string resource)
{
var handler = new HttpClientHandler();
if (handler.SupportsAutomaticDecompression)
{
handler.AutomaticDecompression = System.Net.DecompressionMethods.GZip | System.Net.DecompressionMethods.Deflate;
}
var client = new HttpClient(handler)
{
BaseAddress = new Uri($"https://api.address.com/rest/{resource}")
};
return client;
}
I have this code below code to create a database in couchDB:
private async void DatabaseCreate()
{
if (!await DatabaseExist())
{
var contents = new StringContent("", Encoding.UTF8, "text/plain");
this.uri = "http://USER:PASSWORD#localhost:5984/item_sn";
var response = await client.PutAsync(this.uri, contents); //set the contents to null but same response.
Console.WriteLine(response.Content.ReadAsStrifngAsync().Result);
}
}
My problem is that it is giving me a response with StatusCode:401, saying "Unauthorized". I tried curling it in the terminal and it gives me a successful response. Is there some preconditions I need to set for the httpclient? Or am I using the wrong method. I know there are some third party package for couchDB but for my case I just want to use C#'s httpclient.
Thanks in advance
curl command:
curl -X PUT http://USER:PASSWORD#localhost:5984/item_sn
Looks like in HttpClient class you can include credentials with HttpClientHandler Class with its Credentials property. Take a look at this answer. Try it, maybe that would work.
Here's the code that worked.
public async void DatabaseCreate()
{
if (!await DatabaseExist())
{
var contents = new StringContent("", Encoding.UTF8, "text/plain");
var byteArray = Encoding.ASCII.GetBytes("user:pass");
client.DefaultRequestHeaders.Add("Authorization", "Basic " + Convert.ToBase64String(byteArray));
this.uri = "http://localhost:5984/databasename";
var response = await client.PutAsync(this.uri, contents);
Console.WriteLine(response.Content.ReadAsStringAsync().Result);
}
}
I'm making a really simple call to an API to receive some data. I need to send headers to get authorized also I need to send some content on the body. This is what I came up with :
public async Task<List<LoremIpsum>> LoremIpsumJson()
{
LoremIpsum1 data = null;
try
{
var client = new HttpClient();
//now lets add headers . 1.method, 2.token
client.DefaultRequestHeaders.Add("Method", "LoremIpsumExample");
client.DefaultRequestHeaders.Add("Token", "sometoken");
HttpContent content = new StringContent("{\"Name\":\"John\",\"Surname\":\"Doe\",\"Example\":\"SomeNumber\"}", Encoding.UTF8, "application/json");
// ==edit==
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var response = await client.PostAsync("www.theUrlToTheApi", content);
response.EnsureSuccessStatusCode();
string json = await response.Content.ReadAsStringAsync();
data = JsonConvert.DeserializeObject<QueueInfo>(json);
}
catch(Exception ex)
{
Debug.WriteLine(ex.Message.ToString());
}
return data.data;
Debug.WriteLine(data.data);
}
The app breaks after response.EnsureSuccessStatusCode(); because the request obviously is not successful.
I think I'm really missing something really simple here. How can I do this call?
The error is
StatusCode: 406, ReasonPhrase: 'Not Acceptable'
There could be many reasons for this not working. For instance: keyvalues.ToString() is most likely not putting in the value you want. Seems like you might need to serialize to json rather than just calling .ToString().
Use a tool like postman first and get it working there so you have a working example then try and recreate in C#. It will make your life a lot easier.
For everyone coming here to find a solution.
HttpContent cannot take a header much o less a content-type. There was a typo on adding the content-type which was supposed to be added in HttpClient in this way:
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));