I am using a client to interact with CloudMQTT API. I am trying to create a user but after trying the code provided below, I was not able to create a user. When using the code provided within the Github repository for this project, I noticed that I am unable to make use of a ShouldThrow() method (apparently it should be provided by Fluent Assertions).
I did find a post on StackOverflow which looked very similar to the problem I am having. In the question is mentioned that FluentAssertions does not support async methods. In the example code for the client, however, I can see that the ShouldThrow() method is used regardless of this fact.
How could I get the ShoudldThrow() to work or do I even need it to work (because I think it is only supposed to be required in this code if you are applying unit testing)?
This is what a tried so far:
public static async void CreateCloudUser(ICloudMqttApi client)
{
var users = await client.GetUsers();
Console.WriteLine($"Creating a user. Current users available: {users.Count}");
var expectedUser = new NewUser
{
Password = $"{Guid.NewGuid()}",
Username = $"staging-{Guid.NewGuid()}",
};
var createUserResponse = await client.CreateUser(expectedUser);
createUserResponse.IsSuccessStatusCode.Should().BeTrue();
var actual = await client.GetUser(expectedUser.Username);
actual.Should().NotBeNull();
actual.Username.Should().Be(expectedUser.Username);
//users.Should().Contain(u => u.Username == expectedUser.Username); // <-- This throws an exception as well, but not of importance for this specific question.
Func<Task> verifyUser = async () => await client.GetUser(expectedUser.Username);
verifyUser.ShouldThrow<ApiException>() // <-- Not recognized
.And.StatusCode.Should().Be(HttpStatusCode.NotFound);
Console.WriteLine($"Created a user. Current users available: {users.Count}");
}
The client is defined in the way as provided in the documentation for the client right before calling the method:
var client = CloudMqttApi.GetInstance("username", "password");
The user count will result in the same number before and after executing the method (which obviously should have incremented).
Given the asynchronous nature of the shown code, the syntax should be
//...
var deleteResponse = await client.DeleteUser(expectedUser.Username);
deleteResponse.IsSuccessStatusCode.Should().BeTrue();
Func<Task> verifyUser = async () => await client.GetUser(expectedUser.Username);
var exceptionAssertion = await verifyUser.Should().ThrowAsync<ApiException>();
exceptionAssertion.And.StatusCode.Should().Be(HttpStatusCode.NotFound);
//...
Reference FluentAssertions: Exceptions
Also avoid using async void. Have the function return Task
public static async Task CreateCloudUser(ICloudMqttApi client) {
//...
}
Reference Async/Await - Best Practices in Asynchronous Programming
Related
I am using .net core 6.0. I am getting this error when I am calling same method from different places. I tried calling this method GetEmployeeByEmployeeNumber from inside Index and I dont get any error and the method returns the object employee with value values populated in employee
public async Task<IActionResult> Index()
{
EmployeeInfo employee = await _employeeService.GetEmployeeByEmployeeNumber(up.EmployeeId);
PopulatePDFDoc();
return View();
}
public async Task<EmployeeInfo?> GetEmployeeByEmployeeNumber(string employeeId)
{
List<int> emplyoeeInfoId = new List<int>();
UserPrincipal up = utilities.UserADIdentity.GetADUserInfo(WindowsIdentity.GetCurrent().Name.ToString());
emplyoeeInfoId = _ackContext.EmployeeInfos.Where(e => e.EmployeeNumber == employeeId).OrderBy(e => e.DateFormFilled).Select(e => e.EmployeeInfoId).ToList();
var employee = await _ackContext.EmployeeInfos.Include(e => e.EmergencyInfos.Where(p => p.EmployeeInfoId.Equals(emplyoeeInfoId.LastOrDefault()))).Where(e=>e.EmployeeInfoId.Equals(emplyoeeInfoId.LastOrDefault())).FirstOrDefaultAsync();
return employee;
}
If I call the same method GetEmployeeByEmployeeNumber from inside PopulatePDFDoc(); then I get an error saying System.InvalidOperationException: 'Invalid operation. The connection is closed.'
below is my PopulatePDFDoc
public async void PopulatePDFDoc()
{
AckPackage.Data.PDFPopulate.DocPDF doc = new Data.PDFPopulate.DocPDF();
EmployeeInfo employee = await _employeeService.GetEmployeeByEmployeeNumber(up.EmployeeId);
}
below is the screen shot of the error:
I am new to .net core. Any help on this will be highly appreciated.
You need to await the call to PopulatePDFDoc() inside the Index method.
Like this:
await PopulatePDFDoc();
Always use await when calling an async method!
The reason you’re getting a “connection closed” error, is because the call to PopulatePDFDoc() is not being “awaited”, and the server request ends before the asynchronous method can run.
Also, PopulatePDFDoc() should return Task instead of void, like this:
public async Task PopulatePDFDoc()
Another thing I noticed that may cause you issues is your _ackContext which looks like it's a class-wide member variable based on the snippet you shared, meaning that same context-instance is shared between multiple methods.
However the context itself is actually not "thread safe", as can be read in Microsofts documentation here: https://learn.microsoft.com/en-us/ef/ef6/fundamentals/working-with-dbcontext which means that if multiple async methods use the same context - which they do in your example - you may run into issues.
The recommended approach is to create the context when you need it, and use the using syntax to make sure it's disposed properly after your work is finished. Like this:
using (var ackContext = new EmployeeContext())
{
// Perform data access using the context here
}
Try using that in your GetEmployeeByEmployeeNumber method and see if it helps as well :)
I'm using C# on Unity and Firebase for this project, but I'm not sure that this is a framework problem, more like async-approach-trouble.
I've a method to write data on my firebase database (Firestore), this is the method inside my Database class:
public async void AsyncAddData()
{
User newUser = new User()
{
isConfigured = false,
tag = userName,
accessToken = ""
};
DocumentReference docRef = db.Collection("users").Document(newUser.tag);
await docRef.SetAsync(newUser);
Debug.Log("Added new user " + newUser.tag);
}
This method works perfectly when called from my MainController like: Database.AsyncAddData().
The troubles begin when instead of creating inside the async method the new User variable, I try to pass from my MainController an already existing User variable like Database.AsyncAddData(this.currentUser), so the async method now looks like:
public async void AsyncAddData(User newUser)
{
DocumentReference docRef = db.Collection("users").Document(newUser.tag);
await docRef.SetAsync(newUser);
Debug.Log("Added new user " + newUser.tag);
}
This method CRASHES the entire software. My thoughs after experimenting a little bit is that passing a "sync" variable like currentUser to an async method, is not loable. I think so cause if I do Database.AsyncAddData(new User() { tag = currentUserLoged.tag }), it works.
So now my question is...
How can I pass external variables to an async method?
Already readed related posts and questions:
Async Await Issue for methods with parameters
Unity crashes on async programming with Firebase database
Async await best practices in asynchronous programming
Use "Task" as return type of async function.
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/async-return-types#void-return-type
The Task return type prevents removal of newUser by "caller" method until async ends :
you call asyncmethod with newUser from "caller" method
await suspends processing async method and starts processing "caller" method
the newUser is cleaned at the end of "caller" method
then await ends and async method starts processing
in this case 'newUser' is null and throw exception
In my service layer I wanted to fire multiple methods asynchronously and await for their results.
I tried with one at a time and it is erroring out.
In my service class I called the method like
var _validChapterCodesTask = gd.validateChapterCodeDetails(_input1);
await Task.WhenAll(_validChapterCodesTask);
var _chapterCodeResult = await _validChapterCodesTask;
And in DAL class the method definition looks like
public async Task<IEnumerable<ChapterCodeValidationOutput>> validateChapterCodeDetails(GroupMembershipValidationInput gmvi)
{
Repository rep = new Repository();
if (!gmvi._chapterCodes.All(x => x.Equals("")))
{
var _validChapterCodes = await rep.ExecuteStoredProcedureAsync<Entities.Upload.ChapterCodeValidationOutput>(SQL.Upload.UploadValidation.getChapterCodeValidationSQL(gmvi._chapterCodes),null);
return _validChapterCodes;
}
else
return new List<ChapterCodeValidationOutput>();
}
Error message
Error 208 The await operator can only be used within an async method. Consider marking this method with the async modifier and changing its return type to Task<ARC.Donor.Business.Upload.GroupMembershipValidationOutput>. C:\Users\m1034699\Desktop\Stuart_Upgrade_2.1_New Approach\Stuart_Export_Upload_v2.1\Stuart Web Service\ARC.Donor.Service\Upload\UploadValidationServices.cs 34 13 ARC.Donor.Service
in lines
await Task.WhenAll(_validChapterCodesTask);
var _chapterCodeResult = await _validChapterCodesTask;
What am I doing wrong ?
The error message is very explicit. It is telling you that you're Service class method is incorrectly attempting to use the async keyword. In order to fix this, you should be using "Async all the way" as defined in Stephen Cleary's post on MSDN as a best practice.
For example, if you're service class has a method body that is working with Task or Task<T>, or attempting to use the await keyword the method signature for this corresponding method body must be async (as the async keyword enables a method to use the await keyword). Additionally this method itself should also be Task or Task<T> returning, with very few exceptions to that rule.
Personally, I would alter your DAL class to simply return the operation that represents the asynchronous work without actually awaiting it. If you think about it, the body of the validateChapterCodeDetails method does not actually need to do anything with the results, it just needs to return them (instead of materializing them there). Consider the following:
public Task<IEnumerable<ChapterCodeValidationOutput>>
validateChapterCodeDetails(GroupMembershipValidationInput gmvi)
{
var rep = new Repository();
return gmvi._chapterCodes.All(x => x.Equals(""))
? new List<ChapterCodeValidationOutput>()
: rep.ExecuteStoredProcedureAsync
<Entities.Upload.ChapterCodeValidationOutput>
(SQL.Upload.UploadValidation
.getChapterCodeValidationSQL(gmvi._chapterCodes),null)
}
Since your Task<IEnumerable<ChapterCodeValidationOutput>> variable has already been awaited, you can access the .Result property to get what you're looking for.
Then in your Service class your method would look like this:
public async Task ConsumeAsync()
{
var _validChapterCodesTask = gd.validateChapterCodeDetails(_input1);
await Task.WhenAll(_validChapterCodesTask);
var _chapterCodeResult = _validChapterCodesTask.Result;
// Do something with it...
}
Here is a .NET fiddle that should help to exemplify this for you better.
NOTE
I would also caution using IEnumerable as it pertains to your repo, you should ensure that the results from the Database are not occurring via deferred execution, otherwise you risk the potential for connection issues, i.e.; unintentionally leaving a connection open, or not properly closing one.
In the Service class where you call
var _validChapterCodesTask = gd.validateChapterCodeDetails(_input1);
await Task.WhenAll(_validChapterCodesTask);
var _chapterCodeResult = await _validChapterCodesTask;
add a async to the method signature where await Task.WhenAll(_validChapterCodesTask); is called. And when this method also has a return type you have to wrap this type in a Task like the exception shows:
Task<ARC.Donor.Business.Upload.GroupMembershipValidationOutput>
E.g. if you have the following method:
public GroupMemberShipValidationOutput validate(..) {
...
await Task.WhenAll(_validChapterCodesTask);
...
}
You have to change the method signature to:
public async Task<GroupMemberShipValidationOutput> validate(..) {
...
await Task.WhenAll(_validChapterCodesTask);
...
}
I am testing a method for a service that makes a Web API call. Using a normal HttpClient works fine for unit tests if I also run the web service (located in another project in the solution) locally.
However when I check in my changes the build server won't have access to the web service so the tests will fail.
I've devised a way around this for my unit tests by creating an IHttpClient interface and implementing a version that I use in my application. For unit tests, I make a mocked version complete with a mocked asynchronous post method. Here's where I have run into problems. I want to return an OK HttpStatusResult for this particular test. For another similar test I will be returning a bad result.
The test will run but will never complete. It hangs at the await. I am new to asynchronous programming, delegates, and Moq itself and I've been searching SO and google for a while learning new things but I still can't seem to get past this problem.
Here is the method I am trying to test:
public async Task<bool> QueueNotificationAsync(IHttpClient client, Email email)
{
// do stuff
try
{
// The test hangs here, never returning
HttpResponseMessage response = await client.PostAsync(uri, content);
// more logic here
}
// more stuff
}
Here's my unit test method:
[TestMethod]
public async Task QueueNotificationAsync_Completes_With_ValidEmail()
{
Email email = new Email()
{
FromAddress = "bob#example.com",
ToAddress = "bill#example.com",
CCAddress = "brian#example.com",
BCCAddress = "ben#example.com",
Subject = "Hello",
Body = "Hello World."
};
var mockClient = new Mock<IHttpClient>();
mockClient.Setup(c => c.PostAsync(
It.IsAny<Uri>(),
It.IsAny<HttpContent>()
)).Returns(() => new Task<HttpResponseMessage>(() => new HttpResponseMessage(System.Net.HttpStatusCode.OK)));
bool result = await _notificationRequestService.QueueNotificationAsync(mockClient.Object, email);
Assert.IsTrue(result, "Queue failed.");
}
What am I doing wrong?
Thank you for your help.
You're creating a task but never starting it, so it's never completing. However, don't just start the task - instead, change to using Task.FromResult<TResult> which will give you a task which has already completed:
...
.Returns(Task.FromResult(new HttpResponseMessage(System.Net.HttpStatusCode.OK)));
Note that you won't be testing the actual asynchrony this way - if you want to do that, you need to do a bit more work to create a Task<T> that you can control in a more fine-grained manner... but that's something for another day.
You might also want to consider using a fake for IHttpClient rather than mocking everything - it really depends on how often you need it.
Recommend #Stuart Grassie's answer above.
var moqCredentialMananger = new Mock<ICredentialManager>();
moqCredentialMananger
.Setup(x => x.GetCredentialsAsync(It.IsAny<string>()))
.ReturnsAsync(new Credentials() { .. .. .. });
With Mock.Of<...>(...) for async method you can use Task.FromResult(...):
var client = Mock.Of<IHttpClient>(c =>
c.PostAsync(It.IsAny<Uri>(), It.IsAny<HttpContent>()) == Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK))
);
Try using ReturnsAsync.
In asynchronous methods it works, I believe the basis to solve your problem should be similar.
_mocker.GetMock<IMyRepository>()
.Setup(x => x.GetAll())
.ReturnsAsync(_myFakeListRepository.GetAll());
I'm working on a Nancy/ASP.Net project. I've tried to use WebRequest to get data from other web service and I've implemented the request in an async function. I find a problem that when I try to wait on a task returned from the function, it gets blocked indefinitely. The simplified code looks like this..
using System.Net;
using System.Threading.Tasks;
using Nancy;
public class TestModule : NancyModule{
public TestModule() {
Get["/"] = p => "Hello, world";
Get["/async/"] = p => {
var req = WebRequest.CreateHttp("http://localhost:13254/");
// var responseTask = req.GetResponseAsync(); // this works!
var responseTask = getResponse(req); // this gets blocked!
var waitSuccess = responseTask.Wait(10000);
return waitSuccess ? "Yeah!" : "woooh!";
};
}
async Task<HttpWebResponse> getResponse(HttpWebRequest request) {
return (HttpWebResponse) await request.GetResponseAsync();
}
}
The code uses NancyFx but it happens as well on vanilla ASP.Net page. The service on localhost:13254 is working fine. If I use the task directly returned from request's GetResponseAsync(), the code works fine, but If I wrap it in an async method, it just gets blocked.
Does anyone have any idea what's wrong with the code? :( I can change to use synchronous version but the async function works find in other self-hosting services... so I'd like to use the same code here too if possible..
I describe this deadlock behavior on my blog and in a recent MSDN article.
To fix this, you can either use ConfigureAwait(false) everywhere, or you can use synchronous methods. The ideal solution is to use await all the way and never use Wait or Result, but that may not be possible in your situation (it would only work if Nancy worked with async delegates, i.e., Get["/async/"] = async p => { ... };).
In addition to solutions provided from Stephen, I resolve with just changing synchronization context at the root of Nancy route handler. Given this utility function:
using System;
using System.Threading;
namespace Utility.Async{
static public class TPContext{
static public T Call<T>(Func<T> handler) {
var currentContext = SynchronizationContext.Current;
SynchronizationContext.SetSynchronizationContext(null);
try {
return handler();
}finally {
SynchronizationContext.SetSynchronizationContext(currentContext);
}
}
}
}
Just wrap the handler with this function
Get["/async/"] = p => TPContext.Call(() => {
var req = WebRequest.CreateHttp("http://localhost:13254/");
var responseTask = getResponse(req);
var waitSuccess = responseTask.Wait(10000);
return waitSuccess ? "Yeah!" : "woooh!";
});
and it just works ^^a I don't think I need ASP.Net context.. and actually I hope Nancy'd make its own synchronization context since Nancy conceptually works differently from Asp.net already.