HttpClient.GetAsync immediately throws TaskCanceledException - c#

I had a working code that was returning something from my CommonRestClient(which is simple wrapper for HttpClient):
public async Task<IActionResult> Index()
{
var uri = _baseUri.Concat(AvalancheServiceAdresses.NodeService);
using (var client = new CommonRestClient(uri))
{
var result = await client.GetAsync<List<NodeInfoContract>>(new Uri(NodeServiceConstant.NodesContractUrl, UriKind.Relative), null);
return View(result);
}
}
It worked fine and i was happy. Until I decide to move my code from view in another class, which should incapsulate entire REST logic and provide an OOP API.
So now my index looks like:
public async Task<IActionResult> Index()
{
var nodeInfoContracts = await _configManager.GetNodesList();
return View(nodeInfoContracts);
}
where GetNodesList is
public ConfiguredTaskAwaitable<List<NodeInfoContract>> GetNodesList()
{
var uri = _baseUri.Concat(AvalancheServiceAdresses.NodeService);
using (var client = new CommonRestClient(uri))
{
return client.GetAsync<List<NodeInfoContract>>(new Uri(NodeServiceConstant.NodesContractUrl, UriKind.Relative), null);
}
}
It's clear that provided codes are equal.
But now it always throws an exception when I try to get a result. In my GetAsync method it fails on following line with TaskCanceledException:
var response = await _client.GetAsync(url).ConfigureAwait(false);
But it's interestring: when I place a breakpoint on this line and step over its works fine. So here we have race condition or similar.
Why am I getting it? I tried to place CondigureAwait false/true, combining some code, but it always throws an error when breakpoints are off. I checked timeout which is several minutes, it can't cause this error.

In the second code snippet the client is disposed before the IO completed. Use the first form.

Related

I am not getting any output and i don't know why

using System;
using System.Text;
namespace ConsoleApp7
{
class Program
{
static void Main(string[] args)
{
YourClient client = new YourClient();
client.Put();
}
public class YourClient
{
private readonly HttpClient _client;
public YourClient()
{
_client = new HttpClient();
}
public async Task Put() // must be async
{
using (var request = new HttpRequestMessage(HttpMethod.Put, "https://api.minecraftservices.com/minecraft/profile/name/egg"))
{
request.Headers.Add("Authorization", "Bearer token");
request.Content = new StringContent("body", Encoding.UTF8, "content-type");
using (var response = await _client.SendAsync(request))
{
var data = await response.Content.ReadAsStringAsync();
var code = response.StatusCode;
Console.WriteLine(Convert.ToString(code));
// do something with data
}
}
}
}
}
}
I'm not getting any output and I don't know why. I'm trying to print the response code of the request but nothing is output, is it to do with my method?
I have tried printing hi after Client.Put() and it was printed, so I know that my code is actually running, I just don't know why it isn't printing the status code ...
The excellent comment by Prolog points out one of two issues. If your Console app is built on < C# 7.1 you will need a workaround to prevent the app from exiting (before the request has time to process) so in this case add Console.ReadKey() as the very last line. This will spin the message loop until you hit a key. But this is not the main issue and I would like to offer a couple of debugging tips.
The big issue is this:
If I run your code, your http request is failing and is throwing a System.FormatException
Usually this type of exception is not set to Break when Thrown. (You can verify this by looking in the Exception Settings window.) Unfortunately, this is giving you a silent failure in this case, so you must take matters into your own hands to observe it.
Suggestions for debugging your code
Use a try-catch block around any code that has any likelihood of failing.
Use System.Diagnostics.Debug.Assert which will cause your program to break on a line if any condition expression evaluates to false (but only when you're running in Debug mode not Release mode).
Add output statements to trace execution. Using Debug.WriteLine will send messages to the Output window (but again, only in Debug mode). Alternatively, since we have a Console app here, I'm using the main app window to output trace statements.
Example using 1-3:
public async Task Put() // must be async
{
Console.WriteLine("Begin Put()");
try
{
using (var request = new HttpRequestMessage(HttpMethod.Put, "https://api.minecraftservices.com/minecraft/profile/name/egg"))
{
request.Headers.Add("Authorization", "Bearer token");
request.Content = new StringContent("body", Encoding.UTF8, "content-type");
using (var response = await _client.SendAsync(request))
{
var data = await response.Content.ReadAsStringAsync();
var code = response.StatusCode;
Console.WriteLine(Convert.ToString(code));
// do something with data
}
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.Assert(condition: false, message: ex.Message);
}
Console.WriteLine("End Put()");
}
Now, if I run the code it will break and show what the problem is.
Use the Exception Settings window to turn on all exceptions (if in doubt). Now the code will break on the exact line that is the problem.
Verify that you are Setting Authorization Header of HttpClient correctly as this may be part of the root cause of the exception.
Finally, if you continue after the Debug.Assert you will see the following text in your console which will confirm whether your Put method has had a chance to complete or not.
Hope these suggestions help you solve this problem and future ones!
// This workaround for C# versions below 7.1 attempts to
// mimic an `async Main` method.
static void Main(string[] args)
{
RunAsync();
Console.ReadKey();
}
private static async void RunAsync()
{
YourClient client = new YourClient();
// Put() should be awaited inside an async method
await client.Put();
}

WebApi action method returning null

It's been a whole day and I can't able to find a solution.
My Controller's ActionMethod is working fine when it calls from PostMan.
But when I call it from my Unit Test Method, it keeps returning null.
Here is my code.
I already found an answer on StackOverflow:
https://stackoverflow.com/a/56498657/11425180
But this is not resolving my issue.
Here is my ActionMethod
[HttpPost("register")]
public async Task<IActionResult> RegisterUser([FromBody] CreateUserRequest request)
{
if (!ModelState.IsValid)
return BadRequest(ModelState);
try
{
// Map request with dto and give to service
CreateUserRequestDto createDto = _mapper.Map<CreateUserRequestDto>(request);
CreateUserResponseDto response = await _userService.CreateUser(createDto);
if (response.IsSuccess)
{
Success success = new Success(message: SuccessMessages.UserCreated, data: response);
return Ok(success);
}
Error error = new Error(message: ErrorMessages.UserRegistrationFailed, description: response.Error.Description);
return BadRequest(error);
}
catch (Exception ex)
{
return HandleException(ex);
}
}
Here is my test Class
public class MockAccountControllerTests
{
readonly UserController _accountController;
public MockAccountControllerTests()
{
Mock<IMapper> _mockMapper = new Mock<IMapper>();
Mockers.InitializeMappers(_mockMapper);
UserManager<AppUser> _mockUserManager = Mockers.MockUserManager<AppUser>().Object;
UserRepository _mockUserRepository = new Mock<UserRepository>(_mockUserManager, _mockMapper.Object).Object;
UserService _mockUserService = new Mock<UserService>(_mockUserRepository).Object;
_accountController = new Mock<UserController>(_mockUserService, _mockMapper.Object).Object;
}
[Fact]
public async Task RegisterUser_NullUserNamePassword_ThrowsException()
{
CreateUserRequest request = RequestHelpers.CreateUserRequest(null, null);
IActionResult result = await _accountController.RegisterUser(request);
ObjectResult badRequest = result as ObjectResult;
Assert.NotNull(badRequest);
Assert.True(badRequest is BadRequestObjectResult);
Assert.Equal(StatusCodes.Status400BadRequest, badRequest.StatusCode);
Assert.NotNull(badRequest.Value);
Assert.IsType<Error>(badRequest.Value);
}
}
At this line in my Test Method
var result = await _accountController.RegisterUser(request);
The result is null
I also tried to assign a value of BadRequest to a variable like this
var a = BadRequest("Test Message");
The a is also null in this case.
How this will be corrected?
Am I doing something wrong in my ActionMethod or TestMethod?
Kindly review.
This line is the culprit:
_accountController = new Mock<UserController>(_mockUserService, _mockMapper.Object).Object;
Don't mock your system under test, because then you're not testing your code, but simply whether Moq does what it's supposed to do. And it does: it returns default values (null for reference types) for method calls that aren't SetUp().
So instead initialize it to an actual instance of your controller:
_accountController = new UserController(_mockUserService, _mockMapper.Object);
See also: Test controller logic in ASP.NET Core on learn.microsoft.com.
The only possible explanation is that whatever the type of result, it's not derived from ObjectResult, so casting it to ObjectResult via as results in a null value being returned.
The thing is that, I don't see any output that returns something that doesn't derive from ObjectResult, except in your catch block where you're returning HandleException(ex). It's not clear what the type returned is here, so I can only assume that that's where your problem lies. In short, that needs to return an ObjectResult type. Things like BadRequestResult without Object in their names derive from StatusCodeResult, which shares no lineage with ObjectResult.
It's also worth mentioning that once you get past this assertion, your next will fail. Since you're casting whatever the result is to ObjectResult and saving it to badRequest, the assertion Assert.True(badRequest is BadRequestObjectResult) will always fail, because it will always be ObjectResult, not BadRequestObjectResult.

Microsoft Graph throws Request_ResourceNotFound instead of null/0

I'm an apprentice with 4 months of experience and I got a task to build a holiday request application using data from Microsoft Graph. One of the functions of app is to look up a user'ss manager and display it on the dashboard. Everything was going smooth until my boss logged in. After running Microsoft Graph Query To find out current user Manager, Graph Api returns and error(Request_ResourceNotFound) and breaks whole application instead of returning null or 0. I don't know how to handle that error.
I have tried to return null if the result is null, but that didn't do anything.
This what my controller expects:
var allUsersConnectedToCurrentManagerDisplayName = graphHelper.GetManagerForCurrentUser(userIdToCheck).DisplayName;
var allUsersConnectedToCurrentManagerEmail = graphHelper.GetManagerForCurrentUser(userIdToCheck).UserPrincipalName;
var allUsersConnectedToCurrentManagerId = graphHelper.GetManagerForCurrentUser(userIdToCheck).Id;
Microsoft Graph Helper:
User GetDirectManagerForUser(GraphServiceClient _graphServiceClient, string managerId)
{
using(var task = Task.Run(async() => await _graphServiceClient.Users[managerId].Manager.Request().GetAsync()))
{
while (!task.IsCompleted)
Thread.Sleep(200);
var manager = task.Result as Microsoft.Graph.User;
return manager;
}
}
I was expecting this to return null and just don't display a direct manager for the user without anyone above him.
So you've got a few things going on here.
The first, and the most glaring, issue is that your code is requesting the same User record from Graph three times in a row. Each call you're making to GetDirectManagerForUser is downloading the entire User profile. You want to avoid doing this:
var manager = await graphHelper.GetManagerForCurrentUser(userIdToCheck);
var allUsersConnectedToCurrentManagerDisplayName = manager.DisplayName;
var allUsersConnectedToCurrentManagerEmail = manager.UserPrincipalName;
var allUsersConnectedToCurrentManagerId = manager.Id;
The second issue to avoid is wrapping your request in a Task like that. It adds a lot of complexity to the code, makes it super hard to debug, and isn't necessary. Simply add async Task<> at the method level and let the compiler handle wiring it up for you:
async Task<User> GetDirectManagerForUser(GraphServiceClient _graphServiceClient, string managerId)
Third, your casting the result but not capturing any exceptions (i.e. the 404 your getting). You want to capture these and return an empty User:
var manager = await graphHelper.GetManagerForCurrentUser(userIdToCheck);
var allUsersConnectedToCurrentManagerDisplayName = manager.DisplayName;
var allUsersConnectedToCurrentManagerEmail = manager.UserPrincipalName;
var allUsersConnectedToCurrentManagerId = manager.Id;
async Task<User> GetDirectManagerForUser(GraphServiceClient _graphServiceClient, string managerId)
{
try
{
// Normal path
return await _graphServiceClient
.Users[managerId]
.Manager
.Request()
.GetAsync();
}
catch (Exception)
{
// Something went wrong or no manager exists
var emptyUser = new User();
}
}
You have to catch the exception in order to return null.
I would write the function like this:
public User GetDirectManagerForUser(GraphServiceClient _graphServiceClient, string managerId)
{
//.Result, because this function in synchronious
try
{
var manager = await _graphServiceClient.Users[managerId].Manager.Request().GetAsync().Result;
return manager;
}
catch(Exception)
{
return null;
}
}
You could also make the function async like this:
public async Task<User> GetDirectManagerForUser(GraphServiceClient _graphServiceClient, string managerId)
{
try
{
var manager = await _graphServiceClient.Users[managerId].Manager.Request().GetAsync();
return manager;
}
catch(Exception)
{
return null;
}
}
Why haven't you specified an accessibility level?

Unable to return a value from SignalR Client from a different method

I'm working on a Winforms app that executes SQL Procedures through a SignalR client. I'm relatively new to using SignalR and am still wrapping my head around it.
I start off by running my connection method to establish a connection with my SignalR service. I have two addresses configured ready for when I puslish but the DEV configuration leads to the SignalR service I am hosting locally.
Connection to SignalR (ConnectHub)
private async Task ConnectHub()
{
string hubAddress = "";
#if DEBUG
HubAddress = ConfigurationManager.AppSettings["HubAddress_DEV"];
#else
HubAddress = ConfigurationManager.AppSettings["HubAddress_PROD"];
#endif
if (string.IsNullOrEmpty(hubAddress))
{
MessageBox.Show("Hub Address is missing from configuration.");
}
ConnectionHandler.Client = new HubClient(hubAddress, "MyHub");
ConnectionHandler.Client.MyAlert += ConnectionHandler.ClientOnMyAlert;
ConnectionHandler.Client.ServerErrorEvent += ConnectionHandler.ClientOnServerErrorEvent;
await ConnectionHandler.Client.Connect(new List<string>() {
VehicleInfo.ThisVehicle.WarehouseCode,
VehicleInfo.ThisVehicle.VehicleName
});
}
My client is stored globally in my ConnectionHandler class where my event handlers are also kept. (I have breakpoints on these as I have not implemented them yet)
ConnectionHandler Class
public static class ConnectionHandler
{
public static HubClient Client { get; set; }
public static void ClientOnServerErrorEvent(string error)
{
throw new NotImplementedException(); //Currently not implemented
}
public static async Task ClientOnMyAlert(EnumMyAlertType alerttype, string message, Exception exception)
{
await Task.Yield(); //Currently not implemented
}
}
When I call the code to Invoke the procedure in my SignalR client, it returns a DataTable to me which is the intended result.
Call to SignalR
await ConnectHub();
DataTable dt = await ConnectionHandler.Client.Connection.InvokeCoreAsync<DataTable>(
"FetchStatuses",
new object[0]); //This call works as intended and returns a populated DataTable
StatusInfo = new CStatuses();
All the above code is currently done on the main form, however I wanted to move this call to SignalR into a constructor to try and tidy things up.
The problem comes when I try to move this call into another method, the program hangs as I don't think it has received the return value from SignalR, I have placed a breakpoint beneath it and it is not reached. A TryCatch reveals nothing as it hangs within the "Try" with no exception.
Calling from contructor
public CStatuses()
{
Statuses = new List<CStatus>();
var dataTable = ConnectionHandler.Client.Connection.InvokeCoreAsync<DataTable>("FetchStatuses",
new object[0])
.Result; //My program hangs on this line and proceeds no further
I am at a loss as to why it is doing this when I can get a value from the client from the form and when other members of my team have tried to do the same thing they can make a call to SignalR also from a different method.
Does anyone have any ideas as to how I can make this work?
I realize this has gotten quite long but if I can elaborate on things please let me know
FIXED CODE THANKS TO SOLUTION:
I have moved the code from my CStatuses constructor into a new async method within the same class and called it after initialization. This removes the need for .Result and appears to solve the problem for me.
public async Task PopulateStatuses()
{
var dataTable = await ConnectionHandler.Client.Connection.InvokeCoreAsync<DataTable>("FetchStatuses",
new object[0]);
Statuses = new List<CStatus>();
foreach (DataRow row in dataTable.Rows)
{
var status = new CStatus
{
StatusId = Common.Utility.GetInt16Value(row["StatusID"]),
StatusCode = Common.Utility.GetStringValue(row["StatusCode"]),
Description = Common.Utility.GetStringValue(row["Description"])
};
Statuses.Add(status);
}
}
You are running into a deadlock with the .Result call, I would suggest creating an async method in the CStatuses class and after you initialize your CStatuses class call the websocket for data.

Visual Studio breakpoint inside HttpClient.GetAsync call not getting hit

I'm trying to debug an asynchronous call from a test script inside my .NET webservice, but the breakpoints inside my async call are never getting hit. I even tried putting a Debugger.Break() inside of it. Below is the calling code...
HttpClient client = new HttpClient();
client.BaseAddress = new Uri(ConfigurationManager.AppSettings["BaseAddress"]);
string uri = "/api/Rd_Regions";
// Below is the line of code I want to step into, but it won't step into the 'client.GetAsync(uri)'...
HttpResponseMessage response = await client.GetAsync(uri);
if (response.IsSuccessStatusCode)
{
// Convert the result into business object
// Do stuff...
}
else do other stuff...
and the part of the webservice that should be getting called where the breakpoints are is here, the first is the context of the web api, followed by the method being called. I'd be happy if it stopped in either...
public partial class PIMSContext : DbContext
{
public PIMSContext()
: base(new OracleConnection(Security.ConfigurationReader.GetAppSetting("PIMS")), true)
//: base(new OracleConnection(ConfigurationManager.ConnectionStrings["PIMS"].ConnectionString), true)
etc....
And here is the method that is ultimately called:
// GET: api/RD_REGIONS
public IQueryable<RD_REGIONS> GetRD_REGIONS()
{
// I want the debugger to stop here!
Debugger.Break();
return db.RD_REGIONS;
}
Am I missing something? Is it not possible to step into this asynchronous call?
Any insight is appreciated.
Forgot to update with the answer earlier - it turns out I was accidentally debugging in Release mode (VS2015). Switching to Debug mode fixed it - all breakpoints started behaving as expected.
If i have understood you correctly - all breakpoints listed above are not getting hit? Not in await client.GetAsync(uri); neither in web-service GetRD_REGIONS() ? Is the code following after client.GetAsync not reached?
If it's true - maybe this method is never completed?
await client.GetAsync(uri);
Than it's possible that you are getting an exception in this place. Try to surround your GetAsync method with try/catch and place the breakpoint inside the catch block. Something like this:
...
HttpResponseMessage response = null;
try {
response = await client.GetAsync(uri);
}
catch (Exception e) {
throw e; //breakpoint goes here
}
...
Sometimes, because of your method is asynchronous, unhandled exceptions can't be registered globally by debugger or event-log. You can get this exception only with try/catch.

Categories

Resources