Async/Await deadlock - c#

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;
}
}
}

Related

Code stops when using HttpContent.ReadAsAsync

I am trying to read async from HttpContent but my code exists on this method. It used to work but I recently had to switch to a console app because I wanted to make a discord bot. Does anyone know why the code "stops" when I use this in a console app?
I've tried using an async Main as suggested but it does not work
I am using this code:
public class BazaarInfo
{
[JsonProperty("products")]
public List<BazaarProduct> Products { get; set; }
public static async Task<BazaarInfo> BuildAsync()
{
string url = "https://api.hypixel.net/skyblock/bazaar";
using (HttpResponseMessage response = await ApiHelper.GetApiClient("application/json").GetAsync(url))
{
if (response.IsSuccessStatusCode)
{
BazaarInfo output = await response.Content.ReadAsAsync<BazaarInfo>(); //Stops
return output;
}
else
{
return null;
}
}
}
}
I call it from here:
public class Bazaar
{
public Dictionary<string, BazaarProduct> Products { get; set; }
public static async Task<Bazaar> BuildAsync()
{
var output = new Bazaar();
var bazaarInfo = await BazaarInfo.BuildAsync();
output.Products = bazaarInfo.Products.ToDictionary(product => product.Name);
return output;
}
}
And this:
[Command("bazaar")]
public async Task BuildBzItem ([Remainder]string id)
{
var bazaar = await Bazaar.BuildAsync();
string sellSummary = "";
foreach (var summary in bazaar.Products[id].SellSummary)
sellSummary += summary.Amount + summary.Price;
var builder = new Discord.EmbedBuilder()
{
Description = sellSummary
};
await ReplyAsync("", false, builder.Build());
}
And then here with a discord chat event:
private async Task HandleCommandAsync(SocketMessage arg)
{
var message = arg as SocketUserMessage;
var context = new SocketCommandContext(Client, message);
if (message.Author.IsBot) return;
int argPos = 0;
if(message.HasStringPrefix("!", ref argPos))
{
var result = await Commands.ExecuteAsync(context, argPos, Services);
if (!result.IsSuccess) Console.Write(result.ErrorReason);
}
}
And this event is assigned here:
public static async Task Main(string[] args) => await new Program().RunBotAsync();
private DiscordSocketClient Client { get; set; }
private CommandService Commands { get; set; }
private IServiceProvider Services { get; set; }
public async Task RunBotAsync()
{
Client = new DiscordSocketClient();
Commands = new CommandService();
Services = new ServiceCollection().AddSingleton(Client).AddSingleton(Commands).BuildServiceProvider();
string token = "ODQ1MzE1OTY2OTcxODA1NzI3.YKfL1w.SPXi_0xXbbrMziZ9JWiqHFX4dto";
Client.Log += ClientLog;
await RegisterCommandsAsync();
await Client.LoginAsync(TokenType.Bot, token);
await Client.StartAsync();
await Task.Delay(-1);
}
private Task ClientLog(LogMessage arg)
{
Console.WriteLine(arg);
return Task.CompletedTask;
}
public async Task RegisterCommandsAsync()
{
Client.MessageReceived += HandleCommandAsync;
await Commands.AddModulesAsync(Assembly.GetEntryAssembly(), Services);
}
I've tried using an async Main as suggested but it does not work
If you can't use async Main, then block in the Main method:
public static void Main(string[] args) => new Program().RunBotAsync().GetAwaiter().GetResult();

How to add CORS to .net core 3.2

Since the new .net 3.2 preview no longer has a startup.cs with its ConfigureServices function, I am at a loss to figure out how to implement .AddCors. The old way of adding services essentially was to add, then use a service. It doesn't look like that's the way to do it anymore. What is the proper code to add CORS?
Program.cs
using System.Threading.Tasks;
using Microsoft.AspNetCore.Blazor.Hosting;
using Microsoft.Extensions.DependencyInjection;
using BlazorDemo.Shared;
namespace BlazorDemo
{
public class Program
{
public static async Task Main(string[] args)
{
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.Services.AddSingleton<IDataLayer, DataLayer>();
builder.Services.AddCors(options =>
{
options.AddPolicy("CorsPolicy",
builder => builder
.AllowAnyOrigin());
});
builder.RootComponents.Add<App>("app");
await builder.Build().RunAsync();
}
}
}
Data.cs
namespace BlazorDemo.Shared
{
public class Data
{
public Country[] data { get; set; }
}
}
DataLayer.cs
using System;
using System.Threading.Tasks;
using System.Net.Http;
using Microsoft.AspNetCore.Components;
namespace BlazorDemo.Shared
{
public interface IDataLayer
{
Task<Country[]> FetchCountries(string sortField, bool sortDesc);
Task<Country[]> FetchCountries();
}
public class DataLayer : IDataLayer
{
public DataLayer(HttpClient httpClient)
{
this.httpClient = httpClient;
}
HttpClient httpClient;
public async Task<Country[]> FetchCountries(string sortField, bool sortDesc)
{
var url = $"http://outlier.oliversturm.com:8080/countries?sort[0][selector]={sortField}&sort[0][desc]={sortDesc}&take=10";
var data = await httpClient.GetJsonAsync<Data>(url);
return data.data;
}
public async Task<Country[]> FetchCountries()
{
Country[] Countries;
try
{
var url = $"http://outlier.oliversturm.com:8080/countries";
var data = await httpClient.GetJsonAsync<Data>(url);
Countries = ((Data)data).data;
}
catch (Exception e)
{
Country c = new Country() { name = "DD", areaKM2 = 2, population = 50, _id = e.Message };
Countries = new Country[] { c };
}
return Countries;
}
}
}

C# Integration Testing Errors

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

create database in mongodb using asp.net mvc

I have created a database in mongodb using asp.net mvc but when i look to my database the insertion is failed .I have tested before in a console application and it works correctly but now I don't find the problem when i use mvc!can you help me please
this is my code
//IDeviseRepository
namespace WebApplication6
{
public interface IDeviseRepository
{
Devise Add(Devise devise);
void MongoGoNow();
}
}
//DeviseRepository
namespace WebApplication6
{
public class DeviseRepository : IDeviseRepository
{
public IMongoDatabase db;
public DeviseRepository()
{
MongoClientSettings settings = new MongoClientSettings();
settings.Server = new MongoServerAddress("localhost", 27017);
MongoClient client = new MongoClient(settings);
this.db = client.GetDatabase("bigdata");
var collection = db.GetCollection<Devise>("Devise");
}
public IMongoCollection<Devise> Devise
{
get
{ return db.GetCollection<Devise>("Devise"); }
}
public Devise Add(Devise devise)
{
var collection = db.GetCollection<Devise>("Devise");
collection.InsertOne(devise);
return devise;
}
public void MongoGoNow()
{
var collection = db.GetCollection<Devise>("devise");
var result = TestFind(collection);
result.GetAwaiter().GetResult();
}
static async Task TestFind(IMongoCollection<Devise> MyCollection)
{
var filter = new BsonDocument();
var count = 0;
using (var cursor = await MyCollection.FindAsync(filter))
{
while (await cursor.MoveNextAsync())
{
var batch = cursor.Current;
foreach (var document in batch)
{
count++;
}
}
}
}
public void insertdata()
{
var devise = new Devise();
devise.parité = "euro/dollar";
Devise.InsertOne(devise);
}
}
}
Try updating your insert to:
public void insertdata()
{
try
{
var devise = new Devise();
devise.parité = "euro/dollar";
Devise.InsertOne(devise);
}
catch (Exception ex)
{
//put a breakpoint here
}
}

How do I get CreateUsingInMemory() to work with MassTransit?

Here's my entire code. I think the test should pass, but it fails. I've (unsuccessfully) tried using some of the overloads to Consumer.
using MassTransit;
using NUnit.Framework;
using System.Threading.Tasks;
namespace MassTransitTests
{
public class Message
{
}
public class MessageConsumer : IConsumer<Message>
{
public static int ConsumedCount
{
get;
private set;
}
public Task Consume(ConsumeContext<Message> context)
{
ConsumedCount++;
return Task.FromResult(0);
}
}
[TestFixture]
public class MassTransitTest
{
[Test]
public async Task BasicTestAsync()
{
// Arrange
var control = Bus.Factory.CreateUsingInMemory(configure =>
{
configure.ReceiveEndpoint("myQueue", endpoint =>
{
endpoint.Consumer<MessageConsumer>();
});
});
// Act
using (var handle = control.Start())
{
await control.Publish(new Message());
await control.Publish(new Message());
}
// Assert
Assert.That(MessageConsumer.ConsumedCount, Is.EqualTo(2));
}
}
}
Their documentation shows this, which is what I'm doing:
var busControl = Bus.Factory.CreateUsingInMemory(cfg =>
{
cfg.ReceiveEndpoint("queue_name", ep =>
{
//configure the endpoint
})
});
What am I doing wrong/what I do need to change in my Arrange/Act to get my Assert to work?
After digging through their tests, I found what I was missing:
[1] You need* to await BusHandle.Ready, which I wasn't doing. *(The test works without this - at least the first time I ran it, but that may just be a race condition working in my favor....)
[2] The calls to Publish apparently complete whenever the bus has received the message I'm guessing - not when the handlers/consumers of the message have completed their work. Therefore you need to notify the calling code that the handlers have finished if that's what you're testing. Here's one way to do this - use TaskCompletionSource<T> (similar to what I found in their codebase). Obviously I may not have been perfect in my thread-safety and my lock usage is a bit sledge-hammer-esque, but this illustrates the point:
using MassTransit;
using NUnit.Framework;
using System.Threading.Tasks;
namespace MassTransitTests
{
public class Message
{
}
public class MessageConsumer : IConsumer<Message>
{
public static int TargetConsumedCount
{
get { return _targetConsumedCount; }
set
{
lock (_lock)
{
_targetConsumedCount = value;
CheckTargetReached();
}
}
}
private static void CheckTargetReached()
{
if (_consumedCount >= TargetConsumedCount)
{
_targetReached.SetResult(true);
}
}
public static Task<bool> TargetReached { get; private set; }
private static int _consumedCount;
private static int _targetConsumedCount;
private static TaskCompletionSource<bool> _targetReached;
private static object _lock;
static MessageConsumer()
{
_lock = new object();
_targetReached = new TaskCompletionSource<bool>();
TargetReached = _targetReached.Task;
}
public Task Consume(ConsumeContext<Message> context)
{
lock (_lock)
{
_consumedCount++;
CheckTargetReached();
}
return Task.FromResult(0);
}
}
[TestFixture]
public class MassTransitTest
{
[Test]
public async Task BasicTestAsync()
{
// Arrange
var control = Bus.Factory.CreateUsingInMemory(configure =>
{
configure.ReceiveEndpoint("myQueue", endpoint =>
{
endpoint.Consumer<MessageConsumer>();
});
});
using (var handle = control.Start())
{
await handle.Ready; // [1]
// Act
await control.Publish(new Message());
await control.Publish(new Message());
// Assert
MessageConsumer.TargetConsumedCount = 2;
await MessageConsumer.TargetReached; // [2]
}
}
}
}

Categories