I am trying to build an API that receives a GET request from our website client, then makes a request to Eventbrite's API using out access token and returns the response to the web client.
I am trying to use HttpClient to make the request but it gives my Syste.NullReferenceException.
My code looks like:
public class CANWebsiteV3Controller : ApiController
{
private static readonly HttpClient client = new HttpClient();
private readonly HttpResponse _response;
private readonly HttpRequest _request;
public CANWebsiteV3Controller()
{
/*_response = HttpContext.Current.Response;
_request = HttpContext.Current.Request;*/
}
// GET api/<controller>/5
[Route("api2.0/CANWebsiteV3/GetEvents")]
[HttpGet]
public async void GetEvents()
{
string API_TOKEN = "XXXXXXXXXXXX";
string ORGANIZATION_ID = "YYYYYYYYYY";
string ENDPOINT = "https://www.eventbriteapi.com/v3/organizations/" + ORGANIZATION_ID + "/events/?time_filter=current_future";
try
{
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.TryAddWithoutValidation("authorization", "Bearer XXXXXXXXXXXX");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var res = await client.GetAsync(ENDPOINT);
if (res.IsSuccessStatusCode)
{
string eventResponse = res.Content.ReadAsStringAsync().Result;
var events = JsonConvert.DeserializeObject(eventResponse);
events.WriteToReponse();
}
}
catch(Exception ex)
{
JsonResponse.NewResponse("Could not fetch events: "+ex.Message, false, ErrorType.Generic, HttpStatusCode.BadRequest);
}
}
}
Related
I am trying to login to a website and i need to send the credentials as a payload but I don't understand how payloads are sent.
public class LoginClient
{
private readonly HttpClient _client;
public LoginClient()
{
_client = new HttpClient();
}
public async Task Put()
{
using (var request = new HttpRequestMessage(HttpMethod.Post, $"https://accounts.nike.com/challenge/password/v1"))
{
using (var response = await _client.SendAsync(request))
{
}
}
}
}
You are trying to send Json, use PostAsync to set the content
var client = new HttpClient();
var url = $"https://accounts.nike.com/challenge/password/v1";
var data = new System.Net.Http.StringContent(json, Encoding.UTF8, "application/json");
var response = await client.PostAsync(url, data);
I'm trying to change the proxy that this request would send with but i do not understand how to, note i make the request in the main method by using Client.put(name)
public class Client
{
private readonly HttpClient _client;
public Client()
{
_client = new HttpClient();
}
public async Task Put(string name)
{
var sent = DateTimeOffset.Now.ToUnixTimeMilliseconds();
Console.WriteLine($"Sent: {sent}");
using (var request = new HttpRequestMessage(HttpMethod.Put, $"https://api.minecraftservices.com/minecraft/profile/name/{name}"))
{
request.Headers.Add("Authorization", "Bearer token");
Thread.Sleep(50);
using (var response = await _client.SendAsync(request))
{
var recv = DateTimeOffset.Now.ToUnixTimeMilliseconds();
Console.WriteLine($"Status Code: {response.StatusCode}");
Console.WriteLine($"Recv: {recv}");
Console.WriteLine();
}
}
}
}
I am trying to create a APIcontroller with a HTTPClient that can read from an external API. When I access the API via a link I get the required response however when I try to connect to it from code I get an unauthorised error. I have tried both Bearer token and Basic authorization.
Here is a sample request URL that returns the correct response:
RequestURLWithAuthorizationHeader
Here is the code I have tried.
[Route("api/[controller]")]
[ApiController]
public class FrostMetAPIController : ControllerBase
{
private readonly ILogger<FrostMetAPIController> _logger;
private readonly IHttpClientFactory _httpClientFactory;
private static readonly HttpClient _httpClient = new HttpClient
{
BaseAddress = new Uri("https://frost.met.no/observations/")
};
public FrostMetAPIController(ILogger<FrostMetAPIController> logger, IHttpClientFactory
httpClientFactory)
{
_logger = logger;
_httpClientFactory = httpClientFactory;
}
[HttpGet("values")]
public async Task<string> GetRates()
{
var httpClient = _httpClientFactory.CreateClient();
try
{
var _CredentialBase64 = "XXX-xxx-XXX-xxx";
var url = "sources=SN68290:0";
url += "&referencetime=2019-01-01T12:00:00.000Z/2020-06-30T23:59:59Z";
url += "&elements=wind_speed,%20max(wind_speed%20PT1H)";
url += "&timeoffsets=PT0H";
url += "&timeresolutions=PT1H";
url += "×eriesids=0";
url += "&performancecategories=C";
url += "&exposurecategories=2&levels=10.0";
url = url.Replace(" ", "%20");
_httpClient.DefaultRequestHeaders
.Accept
.Add(newMediaTypeWithQualityHeaderValue("application/json"));
_httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", $"Bearer {_CredentialBase64}");
var response = await _httpClient.GetAsync("v0.jsonld?" + url);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
catch (Exception)
{
throw;
}
}
}
This is how I was able to add the basic authentication token to the request header of the API url and retrieve the required response from the API
var _authenticationToken = Convert.ToBase64String(Encoding.UTF8.GetBytes("xxx-xx-xxxx"));
_httpClient.DefaultRequestHeaders.Authorization = new
AuthenticationHeaderValue("Basic", _authenticationToken);
var response = await _httpClient.GetAsync("v0.jsonld?"+ url);
var payload = response.Content.ReadAsStringAsync();
return payload.Result.ToString();
Thanks to #camiloterevinto for the help.
I,m testing ASP.NET Core app with TestServer, and there are controllers that require cookie auth. I've created test server instance like this:
_testServer = new TestServer(new WebHostBuilder()
.UseEnvironment(CustomEnvironments.Test)
.UseContentRoot(currentDirectory)
.UseStartup<Web.Startup>()
.UseUrls("http://localhost/"));
ApiClient = _testServer.CreateClient();
and now I have to add auth cookie, but it is ignored by server. If the client could be created directly I could pass HttpClientHandler to constractor and set UseCookies to false, and it works, but I can't access the handler when I get client from test server. Is there a way to add auth cookies to test client?
I've found the solution. TestServer has method CreateRequest(string path), it returns RequestBuilder, which allows to insert cookies to header
Using #AlexK's answer for inspiration, combined with information from a blog post (as an aside, this post goes into a lot of other useful details when dealing with other issues when sending requests to the test server), here is one way of getting cookies to work with the TestServer using CreateRequest(string path) based on what I used for my own project.
public class TestWebEnvironment : IDisposable
{
private TestServer Server { get; }
private CookieContainer CookieContainer { get; }
public TestWebEnvironment()
{
var builder = new WebHostBuilder()
.UseEnvironment("Test")
.UseStartup<TestWebStartup>();
Server = new TestServer(builder);
CookieContainer = new CookieContainer();
}
private RequestBuilder BuildRequest(string url)
{
var uri = new Uri(Server.BaseAddress, url);
var builder = Server.CreateRequest(url);
var cookieHeader = CookieContainer.GetCookieHeader(uri);
if (!string.IsNullOrWhiteSpace(cookieHeader))
{
builder.AddHeader(HeaderNames.Cookie, cookieHeader);
}
return builder;
}
private void UpdateCookies(string url, HttpResponseMessage response)
{
if (response.Headers.Contains(HeaderNames.SetCookie))
{
var uri = new Uri(Server.BaseAddress, url);
var cookies = response.Headers.GetValues(HeaderNames.SetCookie);
foreach (var cookie in cookies)
{
CookieContainer.SetCookies(uri, cookie);
}
}
}
public async Task<string> GetAsync(string url)
{
using (var response = await BuildRequest(url).GetAsync())
{
UpdateCookies(url, response);
return await response.Content.ReadAsStringAsync();
}
}
public async Task<string> PostAsync(string url, HttpContent content)
{
var builder = BuildRequest(url);
builder.And(request => request.Content = content);
using (var response = await builder.PostAsync())
{
UpdateCookies(url, response);
return await response.Content.ReadAsStringAsync();
}
}
public void Dispose()
{
Server.Dispose();
}
}
What is the preferred way for handling web api endpoints for each controller?
For example, my MVC controller will be calling different endpoints.
These are the only ones for now, but it could change.
Also, I will be developing this locally and and deploying to development server.
http://localhost:42769/api/categories/1/products
http://localhost:42769/api/products/
public class ProductsController : Controller
{
HttpClient client;
string url = "http://localhost:42769/api/categories/1/products"; //api/categories/{categoryId}/products
public ProductsController()
{
client = new HttpClient();
client.BaseAddress = new Uri(url);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
}
// GET: Products
public async Task<ActionResult> ProductsByCategory()
{
HttpResponseMessage responseMessage = await client.GetAsync(url);
if (responseMessage.IsSuccessStatusCode)
{
var responseData = responseMessage.Content.ReadAsStringAsync().Result;
var products = JsonConvert.DeserializeObject<List<GetProductsByCategoryID>>(responseData);
return PartialView(products);
}
return View("Error");
}
}
Not sure I understand you question or problem, but I would create a wrapper class for the service and then have different methods for each resource that you need to call. Always think SOLID.
Example (written by hand)
public class Client
{
private Uri baseAddress;
public Client(Uri baseAddress)
{
this.baseAddress = baseAddress;
}
public IEnumerable<Products> GetProductsFromCategory(int categoryId)
{
return Get<IEnumerable<Product>>($"api/categories/{categoryId}/products");
}
public IEnumerable<Products> GetAllProducts()
{
return Get<IEnumerable<Product>>($"api/products");
}
private T Get<T>(string query)
{
using(var httpClient = new HttpClient())
{
httpClient.BaseAddress = baseAddress;
var response= httpClient.Get(query).Result;
return response.Content.ReadAsAsync<T>().Result;
}
}
}