C# Integration Testing Errors - c#

I have had some problems with my code is throwing lots of errors during the testing phase (2/10). But I don't understand why. Whereas when I launch my code and access those path everything works fine.
Here is a screenshot of the errors:
Here is my System.cs:
using Shard.Shared.Core;
using System;
using System.Collections.Generic;
namespace Shard.Shared.Web.API
{
public class Systems
{
public List<SystemSpecification> MySystems { get; set; }
}
}
Here is my SystemController.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Shard.Shared.Core;
using Xunit;
namespace Shard.Shared.Web.API.Controllers
{
[ApiController]
[Route("[controller]")]
public class SystemsController : ControllerBase
{
public Systems systemList = new Systems();
public void CreateUniverse()
{
MapGeneratorOptions options = new MapGeneratorOptions
{
Seed = "Val Halla"
};
MapGenerator map = new MapGenerator(options);
var array = map.Generate().Systems.ToArray();
systemList.MySystems = array.ToList();
}
[HttpGet]
public IEnumerable<Systems> Get()
{
CreateUniverse();
/*return Enumerable.Range(1, 5).Select(index => new Systems {
Sectors = map.Generate(),
MySystems = array.ToList()
})*/ yield return systemList;
}
[HttpGet("{sectorName}")]
public IActionResult GetSector(string sectorName)
{
CreateUniverse();
if (String.IsNullOrWhiteSpace(sectorName))
{
return StatusCode(404);
}
SystemSpecification findSector = systemList.MySystems.FirstOrDefault((p) => p.Name == sectorName);
if (findSector == null)
{
return StatusCode(404);
}
return StatusCode(200, findSector);
}
[HttpGet("{sectorName}/planets")]
public IActionResult GetSectorPlanets(string sectorName)
{
CreateUniverse();
if (String.IsNullOrWhiteSpace(sectorName))
{
return StatusCode(404);
}
var findSector = systemList.MySystems.FirstOrDefault((p) => p.Name == sectorName);
if (findSector == null)
{
return StatusCode(404);
}
var planets = findSector.Planets;
if (planets == null)
{
return StatusCode(404);
}
Assert.NotNull(findSector);
return StatusCode(200,planets);
}
[HttpGet("{sectorName}/planets/{planetName}")]
public IActionResult GetSectorPlanets_SpecificPlanet(string sectorName, string planetName)
{
CreateUniverse();
if (sectorName.Trim().Length == 0 || planetName.Trim().Length == 0)
{
return StatusCode(404);
}
else
{
/*var findSector = systemList.MySystems.FirstOrDefault((p) => p.Name == sectorName);
var findPlanetName = findSector.Planets.FirstOrDefault((p) => p.Name == planetName);*/
foreach (SystemSpecification system in systemList.MySystems)
{
if (system.Name == sectorName)
{
foreach (PlanetSpecification planet in system.Planets)
{
if (planet.Name == planetName)
{
return StatusCode(200, planet);
}
}
}
}
return StatusCode(404);
/*if (findSector == null || findPlanetName == null)
{
return StatusCode(404);
}*/
//return StatusCode(200, findPlanetName);
}
}
}
}
I tested all these cases when I launch the program but when it comes to respecting the test cases it's mainly the errors it's displaying that I barely understand. So please I will really appreciate if you guys can help me out.
These are the test cases (BaseIntegrationTests.SectorTests.cs):
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Xunit;
namespace Shard.Shared.Web.IntegrationTests
{
public partial class BaseIntegrationTests<TEntryPoint, TWebApplicationFactory>
{
[Fact]
[Trait("grading", "true")]
[Trait("version", "1")]
public async Task CanReadSystems()
{
using var client = factory.CreateClient();
using var response = await client.GetAsync("systems");
await response.AssertSuccessStatusCode();
var array = await response.Content.ReadAsAsync<JArray>();
Assert.NotEmpty(array);
}
[Fact]
[Trait("grading", "true")]
[Trait("version", "1")]
public async Task SystemsHaveNames()
{
using var client = factory.CreateClient();
using var response = await client.GetAsync("systems");
await response.AssertSuccessStatusCode();
var array = await response.Content.ReadAsAsync<JArray>();
Assert.NotNull(array[0]["name"]);
Assert.Equal(JTokenType.String, array[0]["name"].Type);
}
[Fact]
[Trait("grading", "true")]
[Trait("version", "1")]
public async Task SystemsHavePlanets()
{
using var client = factory.CreateClient();
using var response = await client.GetAsync("systems");
await response.AssertSuccessStatusCode();
var array = await response.Content.ReadAsAsync<JArray>();
Assert.NotNull(array[0]["planets"]);
Assert.Equal(JTokenType.Array, array[0]["planets"].Type);
Assert.NotEmpty(array[0]["planets"]);
}
[Fact]
[Trait("grading", "true")]
[Trait("version", "1")]
public async Task PlanetsHaveNames()
{
using var client = factory.CreateClient();
using var response = await client.GetAsync("systems");
await response.AssertSuccessStatusCode();
var array = await response.Content.ReadAsAsync<JArray>();
Assert.NotNull(array[0]["planets"][0]["name"]);
Assert.Equal(JTokenType.String, array[0]["planets"][0]["name"].Type);
var names = array.SelectTokens("$[*].planets[*].name").Select(token => token.Value<string>());
}
[Fact]
[Trait("grading", "true")]
[Trait("version", "1")]
public async Task PlanetsHaveSizes()
{
using var client = factory.CreateClient();
using var response = await client.GetAsync("systems");
await response.AssertSuccessStatusCode();
var array = await response.Content.ReadAsAsync<JArray>();
Assert.NotNull(array.SelectToken("[0].planets[0].size"));
Assert.Equal(JTokenType.Integer, array.SelectToken("[0].planets[0].size").Type);
Assert.Equal(JTokenType.Integer, array.SelectToken("[0].planets[0].size").Type);
}
[Fact]
[Trait("grading", "true")]
[Trait("version", "2")]
public async Task PlanetsDoNotHaveResources()
{
using var client = factory.CreateClient();
using var response = await client.GetAsync("systems");
await response.AssertSuccessStatusCode();
var array = await response.Content.ReadAsAsync<JArray>();
var allPlanets = array.SelectTokens("[*].planets[*]").Cast<IDictionary<string, JToken>>();
var allProperties = allPlanets.SelectMany(planet => planet.Keys).Distinct();
Assert.DoesNotContain("resource", string.Join(",", allProperties));
}
public async Task<JToken> GetFirstSystem()
{
using var client = factory.CreateClient();
using var systemsResponse = await client.GetAsync("systems");
await systemsResponse.AssertSuccessStatusCode();
var systems = await systemsResponse.Content.ReadAsAsync<JArray>();
var system = systems.FirstOrDefault();
Assert.NotNull(system);
return system;
}
[Fact]
[Trait("grading", "true")]
[Trait("version", "1")]
public async Task CanFetchOneSystem()
{
var system = await GetFirstSystem();
using var client = factory.CreateClient();
using var response = await client.GetAsync("systems/" + system["name"].Value<string>());
await response.AssertSuccessStatusCode();
Assert.Equal(system.ToString(), (await response.Content.ReadAsAsync<JToken>()).ToString());
}
[Fact]
[Trait("grading", "true")]
[Trait("version", "1")]
public async Task CanFetchPlanetsOfOneSystem()
{
var system = await GetFirstSystem();
using var client = factory.CreateClient();
using var response = await client.GetAsync("systems/" + system["name"].Value<string>() + "/planets");
await response.AssertSuccessStatusCode();
Assert.Equal(system["planets"].ToString(), (await response.Content.ReadAsAsync<JToken>()).ToString());
}
[Fact]
[Trait("grading", "true")]
[Trait("version", "1")]
public async Task CanFetchOnePlanet()
{
var system = await GetFirstSystem();
var planet = system["planets"][0];
using var client = factory.CreateClient();
using var response = await client.GetAsync(
"systems/" + system["name"].Value<string>() + "/planets/" + planet["name"].Value<string>());
await response.AssertSuccessStatusCode();
Assert.Equal(planet.ToString(), (await response.Content.ReadAsAsync<JToken>()).ToString());
}
[Fact]
[Trait("grading", "true")]
public async Task NonExistingSectorReturns404()
{
using var client = factory.CreateClient();
using var response = await client.GetAsync("systems");
await response.AssertSuccessStatusCode();
var array = await response.Content.ReadAsAsync<JArray>();
Assert.NotNull(array.SelectToken("[0].planets[0].size"));
Assert.Equal(JTokenType.Integer, array.SelectToken("[0].planets[0].size").Type);
Assert.Equal(JTokenType.Integer, array.SelectToken("[0].planets[0].size").Type);
}
}
}
I can't really figure out the error messages.
Thanks

Related

Dotnet 6 Xunit integration testing EnsureSuccessStatusCode gives Response status code does not indicate success: 500

Hello I'm learning integration testing and I want to test a 'POST' method from my controller using xunit and WebApplicationFactory But I'm getting this exception
System.Net.Http.HttpRequestException : Response status code does not indicate success: 400 (Bad Request).
This is my Test:
using System.Net.Http;
using System.Threading.Tasks;
using Xunit;
using System.Text;
using Newtonsoft.Json;
namespace integrationtest.IntegrationTests;
public class ControllerTest : IClassFixture<TestingWebAppFactory<Program>>
{
private readonly HttpClient _client;
public ControllerTest(TestingWebAppFactory<Program> factory)
=> _client = factory.CreateClient();
[Fact]
public async Task AddAccountTest()
{
var postRequest = new HttpRequestMessage(HttpMethod.Post, "/api/Accounts/Register");
var formModel = new RegisterInputModel{
UserName= "newuser111",
Email = "newuser#example.com",
PhoneNumber = "111222333",
Password= "Gamma2205!",
ConfirmPassword= "Gamma2205!"
} ;
var stringPayload = JsonConvert.SerializeObject(formModel);
postRequest.Content = new StringContent(stringPayload, Encoding.UTF8, "application/json");
var response = await _client.SendAsync(postRequest);
response.EnsureSuccessStatusCode();
response.IsSuccessStatusCode.Equals(true);
var responseString = await response.Content.ReadAsStringAsync();
Assert.Contains("1", responseString);
}
}
This is my controller function
[AllowAnonymous]
[HttpPost]
public async Task<ActionResult<Response>> Register(RegisterInputModel userRegiterModel)
{
HttpContext.Items.Add("action","Accounts.Register");
await _accountsService.Register(userRegiterModel);
return Ok(new ResponseSuccess("User Registered Successfully", "Accounts.Register"));
}
This is the service
public async Task<IdentityResult> Register(RegisterInputModel userRegiterModel)
{
try
{
ApplicationUser registrationUser = new ApplicationUser()
{
Email = userRegiterModel.Email,
UserName = userRegiterModel.UserName,
PhoneNumber = userRegiterModel.PhoneNumber
};
IdentityResult result = await _userManager.CreateAsync(registrationUser, userRegiterModel.Password);
if (!result.Succeeded)
{
IdentityErrorDescriber errorDescriber = new IdentityErrorDescriber();
IdentityError primaryError = result.Errors.FirstOrDefault();
if (primaryError.Code == nameof(errorDescriber.DuplicateEmail))
{
throw new Exception("Email already exists.");
}
else if (primaryError.Code == nameof(errorDescriber.DuplicateUserName))
{
//_logger.LogError($"Username already exists: {registrationUser.UserName}");
throw new Exception("Username already exists.");
}
else
{
throw new Exception(primaryError.Description);
}
}
else
{
return result;
}
}
catch (System.Exception ex)
{
_logger.LogError(ex.ToString());
throw new Exception(ex.Message);
}
}

Azure Function V3 configuration with DI

I have a Azure Function with 2 triggers:
I’m registering IService in my Startup like so:
I need a different configuration in the Service class depending on which trigger that is calling DoWork()? How can I achieve this using DI?
public class Service : IService
{
public Service(/*Configuration to be injected depends on calling trigger */)
{ }
public void DoWork()
{ }
}
Configuration extract:
Thankyou user1672994. Posting your suggestion as an answer so that it will be helpful for other community members who face similar kind of issues.
Below is the example code to implement todo work items where this will be helpful in resolving your issue.
using AZV3CleanArchitecture.Models;
using AZV3CleanArchitecture.Options;
using AZV3CleanArchitecture.Providers;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
namespace AZV3CleanArchitecture.Services
{
public class ToDoItemsService : IToDoItemsService
{
private readonly HttpClient httpClient;
private readonly ToDoItemsServiceOptions toDoItemsServiceOptions;
private readonly ILogger<ToDoItemsService> logger;
public ToDoItemsService(HttpClient httpClient, IOptions<ToDoItemsServiceOptions> toDoItemsServiceOptions, ILogger<ToDoItemsService> logger)
{
this.httpClient = httpClient;
this.toDoItemsServiceOptions = toDoItemsServiceOptions.Value;
this.logger = logger;
}
public async Task<ToDoItem> GetToDoItem(int id)
{
logger.LogInformation($"Retrieving item: {{{Constants.TodoItemId}}}", id);
var getUrl = $"{this.toDoItemsServiceOptions.BaseUrl.TrimEnd('/')}/todos/{id}";
using (var requestMessage = new HttpRequestMessage(HttpMethod.Get, getUrl))
{
using (var response = await this.httpClient.SendAsync(requestMessage))
{
string responseString = await response.Content.ReadAsStringAsync();
logger.LogWarning($"Retrieved item: {{{Constants.TodoItemId}}}. Logged as warning for demo.", id);
return JsonConvert.DeserializeObject<ToDoItem>(responseString);
}
}
}
public async Task<IEnumerable<ToDoItem>> GetAllToDoItems(int id)
{
logger.LogInformation($"Retrieving all todo items");
var getUrl = $"{this.toDoItemsServiceOptions.BaseUrl.TrimEnd('/')}/todos";
using (var requestMessage = new HttpRequestMessage(HttpMethod.Get, getUrl))
{
using (var response = await this.httpClient.SendAsync(requestMessage))
{
string responseString = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<IEnumerable<ToDoItem>>(responseString);
}
}
}
public async Task<ToDoItem> CreateToDoItem(ToDoItem toDoItem)
{
// call service and return the output
return await Task.FromResult(new ToDoItem() { Id = 1, UserId = 1, Title = "Some Dummy Title", Completed = true });
}
public Task<ToDoItem> UpdateToDoItem(ToDoItem toDoItem)
{
throw new System.NotImplementedException();
}
}
}
for further information check the ToDoItemServices link.

How can I get object fill by SignalR Method?

This is my problem :
I want call signalR function from controller to get list of users connected.
In my OnConnected(), OnDisconnected method I collect the correct data but when I create my own method i can't get the list of Users.
I feel I have a problem with my context because my list is empty but I don't know really why.
I have try somes test :
This a counter of number users connected in my application with SignalR.
The list of users is fill with the OnConnected() method and clean with OnDisconnected()
OnConnected() an user is add:
public override async Task OnConnected()
{
var currentCollab = Context.User.Identity.Name.Length > 0 ? Context.User.Identity.Name : "";
var module = Context.QueryString["module"];
if (!string.IsNullOrEmpty(module))
{
SignalRUsers.Add(new UserConnected()
{
ConnectionId = Context.ConnectionId,
UserName = currentCollab,
ModuleActif = module
});
}
await Clients.All.UpdateCountAccueil(SignalRUsers.Count(x => x.ModuleActif.ToUpper().Equals(ModuleName.Accueil.Value)), SignalRUsers.Where(x => x.ModuleActif.ToUpper().Equals(ModuleName.Accueil.Value)));
await base.OnConnected();
}
In this method SignalRUsers the list is filled with all previous connections but as soon as I try to retrieve the values from this list in a method to call it in my controller this list is completely empty (while there are many active connections)
Complete Hub Class :
using System;
using System.Activities.Statements;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using System.Web.Util;
using System.Windows.Forms;
using ConvergenceCore.ServiceSettingsManager;
using ConvergenceDataAccess.ActiveDirectory;
using Microsoft.AspNet.SignalR;
namespace Main
{
public class ChatHub : Hub
{
private static long counterAccueil = 0;
private static long counterParam = 0;
static Dictionary<string, int> CurrentConnections = new Dictionary<string, int>();
static List<UserConnected> SignalRUsers = new List<UserConnected>();
public void Send(string module, string etat, string message)
{
// Call the broadcastMessage method to update clients.
Clients.All.broadcastMessage(module, etat, message);
}
public override async Task OnReconnected()
{
var currentCollab = Context.User.Identity.Name.Length > 0 ? Context.User.Identity.Name : "";
var module = Context.QueryString["module"];
if (!string.IsNullOrEmpty(module))
{
SignalRUsers.Add(new UserConnected()
{
ConnectionId = Context.ConnectionId,
UserName = currentCollab,
ModuleActif = module
});
}
await Clients.All.UpdateCountAccueil(SignalRUsers.Count(x => x.ModuleActif.ToUpper().Equals(ModuleName.Accueil.Value)), SignalRUsers.Where(x => x.ModuleActif.ToUpper().Equals(ModuleName.Accueil.Value)));
await Clients.All.UpdateCountParam(SignalRUsers.Count(x => x.ModuleActif.ToUpper().Equals(ModuleName.Param.Value)), SignalRUsers.Where(x => x.ModuleActif.ToUpper().Equals(ModuleName.Param.Value)));
await Clients.All.UpdateCountRh(SignalRUsers.Count(x => x.ModuleActif.ToUpper().Equals(ModuleName.Rh.Value)), SignalRUsers.Where(x => x.ModuleActif.ToUpper().Equals(ModuleName.Rh.Value)));
await Clients.All.UpdateCountFacturation(SignalRUsers.Count(x => x.ModuleActif.ToUpper().Equals(ModuleName.Facturation.Value)), SignalRUsers.Where(x => x.ModuleActif.ToUpper().Equals(ModuleName.Facturation.Value)));
await base.OnReconnected();
}
public override async Task OnConnected()
{
var currentCollab = Context.User.Identity.Name.Length > 0 ? Context.User.Identity.Name : "";
var module = Context.QueryString["module"];
if (!string.IsNullOrEmpty(module))
{
SignalRUsers.Add(new UserConnected()
{
ConnectionId = Context.ConnectionId,
UserName = currentCollab,
ModuleActif = module
});
}
await Clients.All.UpdateCountAccueil(SignalRUsers.Count(x => x.ModuleActif.ToUpper().Equals(ModuleName.Accueil.Value)), SignalRUsers.Where(x => x.ModuleActif.ToUpper().Equals(ModuleName.Accueil.Value)));
await Clients.All.UpdateCountParam(SignalRUsers.Count(x => x.ModuleActif.ToUpper().Equals(ModuleName.Param.Value)), SignalRUsers.Where(x => x.ModuleActif.ToUpper().Equals(ModuleName.Param.Value)));
await Clients.All.UpdateCountRh(SignalRUsers.Count(x => x.ModuleActif.ToUpper().Equals(ModuleName.Rh.Value)), SignalRUsers.Where(x => x.ModuleActif.ToUpper().Equals(ModuleName.Rh.Value)));
await Clients.All.UpdateCountFacturation(SignalRUsers.Count(x => x.ModuleActif.ToUpper().Equals(ModuleName.Facturation.Value)), SignalRUsers.Where(x => x.ModuleActif.ToUpper().Equals(ModuleName.Facturation.Value)));
await base.OnConnected();
}
public override async Task OnDisconnected(bool stopCalled)
{
var userToDelete = SignalRUsers.FirstOrDefault(x => x.ConnectionId == Context.ConnectionId);
SignalRUsers.Remove(userToDelete);
//CurrentConnections.Remove(module + Context.ConnectionId);
await Clients.All.UpdateCountAccueil(SignalRUsers.Count(x => x.ModuleActif.ToUpper().Equals(ModuleName.Accueil.Value)), SignalRUsers.Where(x => x.ModuleActif.ToUpper().Equals(ModuleName.Accueil.Value)));
await Clients.All.UpdateCountParam(SignalRUsers.Count(x => x.ModuleActif.ToUpper().Equals(ModuleName.Param.Value)), SignalRUsers.Where(x => x.ModuleActif.ToUpper().Equals(ModuleName.Param.Value)));
await Clients.All.UpdateCountRh(SignalRUsers.Count(x => x.ModuleActif.ToUpper().Equals(ModuleName.Rh.Value)), SignalRUsers.Where(x => x.ModuleActif.ToUpper().Equals(ModuleName.Rh.Value)));
await Clients.All.UpdateCountFacturation(SignalRUsers.Count(x => x.ModuleActif.ToUpper().Equals(ModuleName.Facturation.Value)), SignalRUsers.Where(x => x.ModuleActif.ToUpper().Equals(ModuleName.Facturation.Value)));
await base.OnDisconnected(stopCalled);
}
public List<UserConnected> GetListUsersConnected(string module)
{
return SignalRUsers.Where(x => x.ModuleActif == module).ToList();
}
}
public class UserConnected
{
public string UserName { get; set; }
public string ConnectionId { get; set; }
public string ModuleActif { get; set; }
}
}
In my Controller :
public PartialViewResult DetailUsersConnected(string module)
{
ChatHub hub = new ChatHub();
var listUsers = hub.GetListUsersConnected(module);
return PartialView("../Parametrages/Content/_DetailsUserConnected", listUsers);
}
Why is my list empty in my GetListUsersConnected method ?
Why I do not recover met previous connection as in OnConnected() for example ?
Every time a client connects a new instance of the Hub object is created. If your SignalRUsers is a property of the hub, then is created from scratch every time. Try make it a static property or use a Singleton in a container.

Getting HttpClient to POST/PUT Async

I am attempting to PUT and POST to a URL using HttpClient in C#. I need to do so asynchronously for scaling purposes. However, I am only able to get my PUT and POST to work synchronously. Below is the code I am using to PUT the ZoomData objects in JSON format to the URL:
// takes the dataset to PUT and PUTs to server
public async Task<HttpResponseMessage> JsonPUTcall(ZoomData toPut)
{
string jsonString = JsonConvert.SerializeObject(toPut);
return await client.PutAsync(InsiteDatasetPutURL.Replace("sys_id", toPut.sys_id), new StringContent(jsonString, UnicodeEncoding.UTF8, "application/json"));
}
And here is the code I am using to actually pass ZoomData objects in a queue to JsonPUTcall:
public async void JsonPUTqueueCall(Queue<ZoomData> toPut)
{
if (toPut.Count == 0)
return;
foreach (var zoomData in toPut)
{
var result = await this.JsonPUTcall(zoomData);
}
}
However, when I attempt this, it simply hangs. So, as a test, I replaced "var result = await this.JsonPUTcall(zoomData);" with the following:
public async void JsonPUTqueueCall(Queue<ZoomData> toPut)
{
if (toPut.Count == 0)
return;
foreach (var zoomData in toPut)
{
var result = this.JsonPUTcall(zoomData);
result.Wait();
}
}
That works, but since it is synchronous, it defeats the purpose of using async. What am I missing?
this is my API client which is efficiently uses resources and the methods are async
using System;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
//You need to install package Newtonsoft.Json > https://www.nuget.org/packages/Newtonsoft.Json/
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
public class MyApiClient : IDisposable
{
private readonly TimeSpan _timeout;
private HttpClient _httpClient;
private HttpClientHandler _httpClientHandler;
private readonly string _baseUrl;
private const string ClientUserAgent = "my-api-client-v1";
private const string MediaTypeJson = "application/json";
public MyApiClient(string baseUrl, TimeSpan? timeout = null)
{
_baseUrl = NormalizeBaseUrl(baseUrl);
_timeout = timeout ?? TimeSpan.FromSeconds(90);
}
public async Task<string> PostAsync(string url, object input)
{
EnsureHttpClientCreated();
using (var requestContent = new StringContent(ConvertToJsonString(input), Encoding.UTF8, MediaTypeJson))
{
using (var response = await _httpClient.PostAsync(url, requestContent))
{
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
}
}
public async Task<TResult> PostAsync<TResult>(string url, object input) where TResult : class, new()
{
var strResponse = await PostAsync(url, input);
return JsonConvert.DeserializeObject<TResult>(strResponse, new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
});
}
public async Task<TResult> GetAsync<TResult>(string url) where TResult : class, new()
{
var strResponse = await GetAsync(url);
return JsonConvert.DeserializeObject<TResult>(strResponse, new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
});
}
public async Task<string> GetAsync(string url)
{
EnsureHttpClientCreated();
using (var response = await _httpClient.GetAsync(url))
{
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
}
public async Task<string> PutAsync(string url, object input)
{
return await PutAsync(url, new StringContent(JsonConvert.SerializeObject(input), Encoding.UTF8, MediaTypeJson));
}
public async Task<string> PutAsync(string url, HttpContent content)
{
EnsureHttpClientCreated();
using (var response = await _httpClient.PutAsync(url, content))
{
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
}
public async Task<string> DeleteAsync(string url)
{
EnsureHttpClientCreated();
using (var response = await _httpClient.DeleteAsync(url))
{
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
}
public void Dispose()
{
_httpClientHandler?.Dispose();
_httpClient?.Dispose();
}
private void CreateHttpClient()
{
_httpClientHandler = new HttpClientHandler
{
AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip
};
_httpClient = new HttpClient(_httpClientHandler, false)
{
Timeout = _timeout
};
_httpClient.DefaultRequestHeaders.UserAgent.ParseAdd(ClientUserAgent);
if (!string.IsNullOrWhiteSpace(_baseUrl))
{
_httpClient.BaseAddress = new Uri(_baseUrl);
}
_httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(MediaTypeJson));
}
private void EnsureHttpClientCreated()
{
if (_httpClient == null)
{
CreateHttpClient();
}
}
private static string ConvertToJsonString(object obj)
{
if (obj == null)
{
return string.Empty;
}
return JsonConvert.SerializeObject(obj, new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
});
}
private static string NormalizeBaseUrl(string url)
{
return url.EndsWith("/") ? url : url + "/";
}
}
Usage;
using ( var client = new MyApiClient("http://localhost:8080"))
{
var response = client.GetAsync("api/users/findByUsername?username=alper").Result;
var userResponse = client.GetAsync<MyUser>("api/users/findByUsername?username=alper").Result;
}
These 2 lines is to make it synchronous :
var result = this.JsonPUTcall(zoomData);
result.Wait();
To make it async you hate to do that :
var result = await this.JsonPUTcall(zoomData);

Async/Await deadlock

I can't seem to get my code work, although I tried several different approaches. Here is my preferred code snippet:
var client = await ApiClientProvider.GetApiClient();
var freeToPlayChampions = await client.GetChampionsAsync(true, Region);
var championsData = freeToPlayChampions.Select(x =>
client.GetStaticChampionByIdAsync(
(int)x.Id,
platformId: Region));
ConsoleTable.From(await Task.WhenAll(championsData)).Write();
When debugging I see that the code hangs on await Task.WhenAll(championsData). So i tried to make the code more easy:
var client = await ApiClientProvider.GetApiClient();
var freeToPlayChampions = await client.GetChampionsAsync(true, Region);
var table = new ConsoleTable();
foreach(var freeToPlayChampion in freeToPlayChampions)
{
var championsData = client.GetStaticChampionByIdAsync(
(int)freeToPlayChampion.Id,
platformId: Region);
table.AddRow(await championsData);
}
table.Write();
Unfortunately this hangs, as well. Again on the same code part, e.g. await championsData.
How can this 'easy' usage of async/await lead to an deadlock? Thanks in advance for help!
EDIT:
Here is the whole class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ConsoleTables;
using Mono.Options;
using RiotNet.Models;
using RiotShell.Properties;
namespace RiotShell
{
public class FreeToPlay : IShellCommand
{
public IEnumerable<string> Names { get; }
public OptionSet Options { get; }
public bool ShowHelp { get; private set; }
public string Region { get; private set; }
public FreeToPlay()
{
Names = new List<string>
{
"freetoplay",
"ftp"
};
Options = new OptionSet
{
{ "r|region=" , "The region to execute against", x => Region = x},
{ "h|help|?" , "Show help", x => ShowHelp = true }
};
}
public async Task Execute(IEnumerable<string> args)
{
if (ShowHelp)
{
Options.WriteOptionDescriptions(Console.Out);
return;
}
if (args.Any())
{
throw new Exception(Resources.TooManyArgumentsProvided);
}
if (Region == null)
{
throw new Exception(string.Format(Resources.RequiredOptionNotFound, "region"));
}
if (!PlatformId.All.Contains(Region))
{
throw new Exception(string.Format(Resources.InvalidRegion, Region));
}
var client = await ApiClientProvider.GetApiClient();
var freeToPlayChampions = await client.GetChampionsAsync(true, Region);
var championsData = freeToPlayChampions.Select(x =>
client.GetStaticChampionByIdAsync(
(int)x.Id,
platformId: Region));
ConsoleTable.From(await Task.WhenAll(championsData)).Write();
}
}
}
And here is the caller code, my main method:
using System;
using System.Threading.Tasks;
using RiotShell.Properties;
namespace RiotShell
{
public class Program
{
public static async Task Main()
{
while (true)
{
Console.Write(Resources.RiotShellLineString);
var input = Console.ReadLine();
try
{
var parsedArgs = InputParser.Parse(input);
(var command, var commandArgs) = ArgsToIShellCommandCaster.GetCommand(parsedArgs);
await command.Execute(commandArgs);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
}
}
Since it was wished, here the code for the ApiProvider:
using RiotNet;
using System.Threading.Tasks;
namespace RiotShell
{
public class ApiClientProvider
{
private static IRiotClient _client;
public static async Task<IRiotClient> GetApiClient()
{
if (_client != null)
{
_client.Settings.ApiKey = await KeyService.GetKey();
return _client;
}
_client = new RiotClient(new RiotClientSettings
{
ApiKey = await KeyService.GetKey()
});
return _client;
}
}
}

Categories