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();
}
}
}
}
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 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);
}
}
}
This is my method
static public async Task<string> Get(string token, string url)
{
HttpClient httpclient = new HttpClient();
using (HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, url))
{
request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
request.Headers.Host = "api.ws.sonos.com";
var response = await httpclient.SendAsync(request);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
}
and this is how I call it in my main
namespace ApiTest
{
internal class Program
{
static void Main(string[] args)
{
Console.WriteLine(ApiConnect.Get("My Access Token", "https://api.ws.sonos.com/control/api/v3/households").Result);
I'm try to get the list of households registered to my account but I get a 404 error.
You are not sending your client key or setting the content type to json.
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();
}
}
We have a few classes in our C# project that make calls out to 3rd party APIs. We're using HttpClient objects for the calls. We've set up our classes where we do these calls to accept an HttpClient so that when testing, we can use a custom/fake DelegatingHandler with the client.
We've set up our classes like this:
public class CallingService : ApiService
{
private readonly ISomeOtherService _someOtherService;
public CallingService (ILogger logger,
IConfigurationManager configurationManager,
ISomeOtherService someOtherService) : base(logger, configurationManager)
{
_someOtherService = someOtherService;
}
public CallingService (ILogger logger,
HttpClient client,
IConfigurationManager configurationManager,
ISomeOtherService someOtherService) : base(logger, configurationManager, client)
{
_someOtherService = someOtherService;
}
private async Task<XmlNodeList> TransmitToApi(string xml_string)
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls12;
//..
string type = "application/xml";
var content = new StreamContent(new MemoryStream(Encoding.ASCII.GetBytes(xml_string)));
var targetUri = new Uri(ConfigurationManager.GetAppSetting("ApiUrl"));
var message = new HttpRequestMessage
{
RequestUri = targetUri ,
Method = HttpMethod.Post,
Content = content
};
message.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("*/*"));
message.Content.Headers.Add("Content-Type", type);
message.Headers.Add("someHeader", someData);
HttpResponseMessage response = null;
try
{
// Define the cancellation token.
CancellationTokenSource source = new CancellationTokenSource();
CancellationToken token = source.Token;
response = await Client.SendAsync(message, token);
}
catch (Exception ex)
{
throw ex;
}
//...
return someData;
}
The base ApiService class defines a generic HttpClient object if one is not provided.
We're currently using SendAsync so we can define the message headers. (We have more headers than are listed here.)
The test defines the DelegatingHandler like this:
public class FakeResponseHandler : DelegatingHandler
{
private readonly Dictionary<Uri, HttpResponseMessage> _fakeResponses = new Dictionary<Uri, HttpResponseMessage>();
public void AddFakeResponse(Uri uri, HttpResponseMessage responseMessage, string content = "", bool asXml = false)
{
if (!string.IsNullOrWhiteSpace(content))
{
if (asXml)
{
responseMessage.Content = new StringContent(content, Encoding.UTF8, "application/xml");
}
else
{
responseMessage.Content = new StringContent(content, Encoding.UTF8, "application/json");
}
}
_fakeResponses.Add(uri, responseMessage);
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
if (_fakeResponses.ContainsKey(request.RequestUri))
{
return _fakeResponses[request.RequestUri];
}
return new HttpResponseMessage(HttpStatusCode.NotFound) { RequestMessage = request };
}
}
And then:
[Fact]
public async Task ItWillDoStuffAndCallApi()
{
using (var mock = AutoMock.GetLoose())
{
mock.Mock<IConfigurationManager>()
.Setup(cm => cm.GetAppSetting("ApiUrl"))
.Returns("http://example.org/test/");
string testReturnData = GetFileContents("IntegrationTests.SampleData.SampleApiResponseXML.txt");
FakeResponseHandler fakeResponseHandler = new FakeResponseHandler();
fakeResponseHandler.AddFakeResponse(new Uri("http://example.org/test/"),
new HttpResponseMessage(HttpStatusCode.OK),
testReturnData,
true);
//HttpClient httpClient = new HttpClient(fakeResponseHandler);
HttpClient httpClient = HttpClientFactory.Create(fakeResponseHandler);
mock.Provide(httpClient);
var ourService = new CallingService();
ourService.TransmitToApi(someXmlString);
}
}
When we run the test, we receive the message:
Handler did not return a response message.
And we never seem to get into DelegatingHandler.SendAsync method.
We have other classes calling APIs using HttpClient.PostAsync or GetAsync, and these do call the DelegatingHandler.SendAsync method and work as expected.
We've tried:
HttpClient httpClient = new HttpClient(fakeResponseHandler);
and
HttpClient httpClient = HttpClientFactory.Create(fakeResponseHandler);
We've also tried Client.SendAsync with and without the cancellation token.
Why is this not working?
Should we re-write this to use PostAsync?
I'd need to see the implementation of HttpClientFactory.Create and what Client.SendAsync actually does internally but nevertheless I was able to use the sample code you provide and fill in the blanks where I could to get the following to work:
public class FakeResponseHandler : DelegatingHandler
{
private readonly Dictionary<Uri, HttpResponseMessage> _fakeResponses = new Dictionary<Uri, HttpResponseMessage>();
public void AddFakeResponse(Uri uri, HttpResponseMessage responseMessage, string content = "", bool asXml = false)
{
if (!string.IsNullOrWhiteSpace(content))
{
if (asXml)
{
responseMessage.Content = new StringContent(content, Encoding.UTF8, "application/xml");
}
else
{
responseMessage.Content = new StringContent(content, Encoding.UTF8, "application/json");
}
}
_fakeResponses.Add(uri, responseMessage);
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var emptyContent = string.Empty;
if (request.Content.Headers.ContentType.MediaType == "application/xml")
emptyContent = "<empty />";
return Task.FromResult(_fakeResponses.ContainsKey(request.RequestUri) ?
_fakeResponses[request.RequestUri] :
new HttpResponseMessage(HttpStatusCode.NotFound)
{
RequestMessage = request,
Content = new StringContent(emptyContent)
});
}
}
Just to make things clean use Task.FromResult to return a task in SendAsync and also provide an empty content to avoid null reference exceptions.
public class CallingService
{
private readonly HttpClient _httpClient;
private readonly IConfigurationManager _configurationManager;
public CallingService(HttpClient httpClient,
IConfigurationManager configurationManager)
{
_httpClient = httpClient;
_configurationManager = configurationManager;
}
public async Task<XmlNodeList> TransmitToApi(string xml_string)
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls12;
//..
string type = "application/xml";
var content = new StreamContent(new MemoryStream(Encoding.ASCII.GetBytes(xml_string)));
var targetUri = new Uri(_configurationManager.GetAppSetting("ApiUrl"));
var message = new HttpRequestMessage
{
RequestUri = targetUri,
Method = HttpMethod.Post,
Content = content
};
message.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("*/*"));
message.Content.Headers.Add("Content-Type", type);
string somedata;
try
{
// Define the cancellation token.
CancellationTokenSource source = new CancellationTokenSource();
CancellationToken token = source.Token;
var response = await _httpClient.SendAsync(message, token);
somedata = await response.Content.ReadAsStringAsync();
}
catch (Exception ex)
{
throw ex;
}
//...
var xmlDoc = new XmlDocument();
xmlDoc.LoadXml(somedata);
return xmlDoc.SelectNodes("*");
}
}
And then the test passes the instance of HttpClient to CallingService:
[TestMethod]
public async Task TestMethod1()
{
const string content = #"<root><test>1243</test></root>";
const string httpExample = "http://example.org/test/";
var configurationManager = new Mock<IConfigurationManager>();
configurationManager
.Setup(cm => cm.GetAppSetting("ApiUrl"))
.Returns(httpExample);
var fakeResponseHandler = new FakeResponseHandler();
fakeResponseHandler.AddFakeResponse(new Uri(httpExample),
new HttpResponseMessage(HttpStatusCode.OK), content, true);
using (var httpClient = new HttpClient(fakeResponseHandler))
{
var ourService = new CallingService(httpClient, configurationManager.Object);
var result = await ourService.TransmitToApi(content);
Assert.AreEqual(content, result.Item(0)?.OuterXml);
}
}
This all works so if I had to guess - the issue would be somewhere in your HttpClientFacotry.
Hope that helps!! Cheers, :)