Why the following code doesn't run without await keyword? - c#

I have a method called myMethodAsync, which needs to be executed, make some stuff and then run DoSomeWork method - however it doesn't need to wait until the method is done.
It's an asp.net core 2.0 application using Entity Framework Core and the built-in dependency injection. Every class in the sample is Scoped. I'm using repository pattern. There is no error, just nothing is happening If I set breakpoint after myRepository.GetAsync or in the GetAsync method the debugger doesn't get in.
The code:
public async Task myMethodAsync
{
...
await myRepository.AddAsync(entity);
DoSomeWork(id); // If it's lack of await the line below will not works
}
private async Task DoSomeWork(Guid id)
{
...
var someEntity = await myRepository.GetAsync(id); // This line will never be done
}
I thought that it's because the myRepository is shared somehow, so I extracted the DoSomeWork to other class with own myRepository, but the effect is the same.
Also If I use Task.Run nothing changes.
How do I know that the code is never executed? Beacuse I'm changing the entity and updating it to database later. However the entity is not changed.
Also really intersting is that this following code almost works:
public async Task myMethodAsync
{
...
await myRepository.AddAsync(entity);
DoSomeWork(id); // Now it almost works
await myRepository.GetAsync(randomID);
}
private async Task DoSomeWork(Guid id)
{
...
var someEntity = await myRepository.GetAsync(id); // It works now
...
await myRepository.UpdateAsync(entity); // But it doesn't work
}

I've found a solution. The problem was with EF - my DbContext was disposed(it didn't throw an exception cause of multi-threading I think). I needed to implement ICloneable interface to DbContext and myRepository. Now I'm passing cloned version of myRepository and everything works fine.
public async Task myMethodAsync
{
...
await myRepository.AddAsync(entity);
DoSomeWork(id, (Repository)myRepository.Clone());
}
private async Task DoSomeWork(Guid id, Repository clonedRepository)
{
...
var someEntity = await clonedRepository.GetAsync(id);
}

Related

xUnit Theory with async MemberData

I have a unit test project using xUnit.net v.2.3.1 for my ASP.NET Core 2.0 web app.
My test should focus on testing a given DataEntry instance: DataEntry instances are generated by the async method GenerateData() in my DataService class, which looks like:
public class DataService {
...
public async Task<List<DataEntry>> GenerateData() {
...
}
...
}
I am writing this test case as a Theory so my test can focus on a DataEntry instance at a time. Here is the code:
[Theory]
[MemberData(nameof(GetDataEntries))]
public void Test_DataEntry(DataEntry entry) {
// my assertions
Assert.NotNull(entry);
...
}
public static async Task<IEnumerable<object[]>> GetDataEntries() {
var service = new DataService();
List<DataEntry> entries = await service.GenerateData().ConfigureAwait(false);
return entries.Select(e => new object[] { e });
}
However, I get the following error at compile time:
MemberData must reference a data type assignable to 'System.Collections.Generic.IEnumerable<object[]>'. The referenced type 'System.Threading.Tasks.Task<System.Collections.Generic.IEnumerable<object[]>>' is not valid.
From the error description, it seems xUnit.net does not allow MemberData to use an async static method, like my GetDataEntries() one. Is there any functionality gap in xUnit.net I should be aware of?
Now, I know I could switch my Theory into a Fact and loop through each DataEntry in the list returned by my DataService, however I would prefer to keep a Theory setup as my test would be cleaner and focused on DataEntry instead of List<DataEntry>.
Question: is there any way in xUnit.net to let my Theory get data from my DataService async API? Please, note the DataService class cannot be changed nor extended to provide data synchronously.
EDIT
I am looking for a way through async/await and would prefer to avoid any usage of blocking calls such as Task<T>.Result e.g. on my GenerateData() method, as the underlying thread will be blocked til the operation completes.
This is relevant in my test project as I have other similar test cases where data should be retrieved in the same way and therefore I want to avoid ending up with too many blocking calls, but instead keeping the async/await propagation.
Until xUnit allows async theory data, you can use Task<T> instances as theory data and await them inside the test method (note that test methods can be async):
public static IEnumerable<object> GetDataEntries() {
var service = new DataService();
yield return new object[] { service.GenerateData() };
}
[Theory]
[MemberData(nameof(GetDataEntries))]
public async Task Test_DataEntry(Task<List<DataEntry>> task) {
List<DataEntry> entries = await task;
for (int i = 0; i < entries.Count; i++) {
// my assertions
Assert.NotNull(entries[i]);
}
}
This functionality is not provided internally. You can try following:
Write your CustomMemberDataAttribute by inheriting DataAttribute.
Override 'GetData' method of parent class.
Make the method async, that, provides data.
Call async data provider method from 'GetData' method.
Use your CustomMemberDataAttribute to decorate test cases.
You can refer following link to write your custom attribute.
Keep other method same, just modify 'GetData' method as discuss above.
https://github.com/xunit/xunit/blob/bccfcccf26b2c63c90573fe1a17e6572882ef39c/src/xunit.core/MemberDataAttributeBase.cs

Convert conventional method to Asynchronous

I have an API which is responsible for inserting text message details in database.
It does by making synchronous call to repository which I think could be implemented asynchronous way.How can I achieve this? Or what could be the best way to handle this scenario.Code snippet example is highly appreciated as I am still getting my ahead wrapping around .NET.
api:
public IHttpActionResult SendSMSNotification([FromBody] SMSNotification smsNotification)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
_service.SendSMS(smsNotification);
return Ok();
}
Service:
internal void SendSMS(SMSNotification smsNotification)
{
_repository.Notify(_mapperService.GetSMSNotification(smsNotification));
}
mapper:
public SMSNotification GetSMSNotification(SMSNotification message)
{
return AutoMapper.Mapper.Map<SMSNotification>(message);
}
repo:
public virtual bool Notify(SMSNotification request)
{
using (var sql = _sqlMapper.CreateCommand('Database', 'Stored proc'))
{
sql.AddParam("#fMessage", request.Message);
//..............
//.............. more params
var retvalParamOutput = sql.AddOutputParam("#fRetVal", System.Data.SqlDbType.Int);
sql.Execute();
return retvalParamOutput.GetSafeValue<int>() == 1;
}
}
sql here is a custom thing and it has following methods:
public static int Execute(this IDataCommand #this);
[AsyncStateMachine(typeof(<ExecuteAsync>d__1))]
public static Task<int> ExecuteAsync(this IDataCommand #this);
Changing a blocking, typically IO-bound call (such as database, network or file system work) to async can make your app scale better.
This does have a flow-on affect through your API. That is, you need to be awaiting on asynchronous calls all the way up to the top-most call, otherwise, somewhere is going to block and you're just lost the benefit of calling an async API.
To demonstrate that, let's start from the bottom at the repository call, as that's the possibly expensive blocking operation can be made async. We alter sql.Execute to use the asynchronous version ExecutAsync version instead:
repo:
public virtual async Task<bool> Notify(SMSNotification request)
{
using (var sql = _sqlMapper.CreateCommand('Database', 'Stored proc'))
{
sql.AddParam("#fMessage", request.Message);
//..............
//.............. more params
var retvalParamOutput = sql.AddOutputParam("#fRetVal", System.Data.SqlDbType.Int);
await sql.ExecuteAsync();
return retvalParamOutput.GetSafeValue<int>() == 1;
}
}
Now here we have to change the signature of the method to return a Task wrapping a result of bool.
We also mark the method as async, so then we can use the "await" operator further down. Without doing this, we'd have to do more refactoring to manipulate and return the Task result ourselves, but the "async" modifier and "await" keyword let the compiler do that magic for us, and the rest of our code mostly looks like normal.
The mapper call doesn't really need to change:
mapper:
public SMSNotification GetSMSNotification(SMSNotification message)
{
return AutoMapper.Mapper.Map<SMSNotification>(message);
}
The service call is now making a call to an async method, so because we want to await and not block on that async call, we have to also change this previously void method to an async method. Note we change it from "void" to "async Task"; you CAN mark a void method as "async void", but that's intended as a workaround for event handlers in Windows Forms and WPF apps; in every other case you want to change a "void" method to "async Task" when making it async.
Service:
internal async Task SendSMS(SMSNotification smsNotification)
{
await _repository.Notify(_mapperService.GetSMSNotification(smsNotification));
}
Then finally, our API call can be made async, and await our service call:
api:
public async Task<IHttpActionResult> SendSMSNotification([FromBody] SMSNotification smsNotification)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
await _service.SendSMS(smsNotification);
return Ok();
}
It's sometimes recommended that after you do a refactor like this, to rename the methods to end in "Async" by convention; however I don't think this is really compulsory, as so much of the .NET API surface is becoming async, it's almost redundant now.
It's worth getting your head around the async / await stuff though; I've tried to keep the example relatively brief. But I hope this at least gets you started.

Load data (async/await)

I'm not sure about this state. I need to get data from database asynchrony.
I have class DB
public class Db{
public async Task<ObservableCollection<Person>> GetAllPerson()
{
using (var context = new Db())
{
// get data and return ObservableCollection<Person>
}
}
}
In the ViewModel I call LoadData function.
public class VM{
public ObservableCollection<Person> Person { get; set; }
private readonly DB sqlRepository;
public VM()
{
sqlRepository=new DB();
LoadData();
}
private async void LoadData()
{
Person= await sqlRepository.GetAllPerson();
}
}
I got warning: Warning CS1998 This async method lacks 'await' operators and will run synchronously.
How can I run my function asynchronously?
Should I use ?
Person=await Task.Run(()=>this.sqlRepository.GetAllPerson());
How can I run my function asynchronously?
You're approaching your problem from the wrong direction. You're trying to go "outside in" - your ViewModel wants to load the database data asynchronously. And that's a fine way of describing the problem, but it's the wrong way to solve it.
To solve it more easily, start at the other end. Whatever methods are actually calling into the database (e.g., Entity Framework calls) should be made asynchronous first, and then let async grow out from there. Eventually you'll end up with something like:
public async Task<ObservableCollection<Person>> GetAllPersonAsync()
{
using (var context = new Db())
{
// This code wasn't shown in the question.
// But from the compiler warning, it was probably using something like
// var people = People.ToList();
// return new ObservableCollection<Person>(people);
// And the async version should be:
var people = await People.ToListAsync();
return new ObservableCollection<Person>(people);
}
}
Which you could consume as:
private async void LoadData()
{
Person = await sqlRepository.GetAllPersonAsync();
}
But I recommend consuming it via NotifyTask as described in my MVVM async data binding article. That approach would give you the ability to data-bind busy spinners and whatnot.
Should I use [Task.Run]?
No. That's "fake asynchrony" - where your code acts like it's asynchronous but it's really just synchronously running on a background thread.

NUnit async Setup not supported?

I need to unit test a method which loads with data in async fashion.
I can easily run async tests methods via
[Test]
public async Task My_test_async() {
// ... await something
}
But I also want the Setup method to be async. Because it prepares some data in mocked Db. This mocked db is of course also async (it has to implement the same interface).
So my setup method looks like this:
[Setup]
public async Task Setup() {
var db = new InMemoryDbContext();
// ... add sample data in db context
// ... then save them
await db.SaveChangesAsync();
}
But this results in my tests being skipped by NUnit Runner
I am using NUnit version 3.0.1, NUnitTestAdapter.WithFramework version 2.0.0 and VisualStudio 2015 with Resharper 9.2
Possible workarounds
I can workaround this problem, but neither solution feels nice.
Workaround #1
Refactor Setup() method to be private, remove the [Setup] attribute from it, and call it in every test method. That way it can be awaited and tests will execute.
Workaround #2
Or I can make the Setup synchronous, and wrap the async code in Task.Run().Result, like this
var r = Task.Run(() => db.SaveChangesAsync()).Result;
But both workarounds are ugly.
Does anyone knows a better solution?
In NUnit3
[OneTimeSetUp]
public async Task OneTimeSetup()
{
// fixture one time setup code, can use await here
}
[SetUp]
public async Task Setup()
{
// per test setup, can use await here
}
Work around #2 :D
[SetUp]
public void Setup()
{
SetupAsync().Wait();
}
public async Task SetupAsync()
{
var db = new InMemoryDbContext();
// ... add sample data in db context
// ... then save them
await db.SaveChangesAsync();
}

How to seed Users in ASP.NET 5 Startup.cs with Async

I'm attempting to create an initial 'Super User' in an ASP.NET 5 application. Using the latest template files with MVC 6 / EF7.
I can follow the examples set out here:
http://wildermuth.com/2015/3/17/A_Look_at_ASP_NET_5_Part_3_-_EF7
This works fine - until I try to execute an async method. For example:
await _userManager.CreateAsync(user, "P#55w0rd!");
or even:
await _context.SaveChangesAsync();
Synchronous methods work without a problem and this code executes outside of the Startup.cs Configure{...} as well.
I get the 'White Screen of Death' on application start. I would do it all without async but I don't think the UserManager has a Create()in Identity 3.0.
Is this me not understanding asynchronous programming or should it be possible?
EDIT: Added the entire call:
Define a Seeder class and a method to create the user:
public class Seeder
{
private ApplicationDbContext _context;
private UserManager<ApplicationUser> _userManager;
public Seeder(
ApplicationDbContext context,
UserManager<ApplicationUser> userManager)
{
_context = context;
_userManager = userManager;
}
public async Task Seed()
{
await CreateUsersAsync();
}
public async Task CreateUsersAsync()
{
var user = await _userManager.FindByEmailAsync("superuser#superuser.com");
if (user == null)
{
var company = _context.Company.First(x => x.Name == "Acme Ltd");
user = new ApplicationUser
{
UserName = "superuser#superuser.com",
Email = "superuser#superuser.com",
CreatedDate = DateTime.Now,
IsActive = true,
CompanyID = company.CompanyId
};
await _userManager.CreateAsync(user, "P#55w0rd!!");
}
}
}
Configure the service:
public void ConfigureServices(IServiceCollection services)
{
...
services.AddTransient<Seeder>();
...
}
Call it:
public async void Configure(Seeder seeder)
{
...
await seeder.Seed();
...
}
Funny thing is; it does actually create the User - it just doesn't continue. So the second time it executes user != null and it executes fine.
I think the problem is because a deadlock is formed by the signature
public async void Configure(Seeder seeder).
Since it returns void, the awaited Task is never returned to the caller which creates a dead lock. Can you make it:
public async Task Configure(Seeder seeder).
I haven't gotten to work with MVC 6 yet, :( so I may be missing something. But that's why there is a deadlock.
Edit:
Since you can't change the signature of Configure, create a method called ConfigureAsync that returns type Task. Now await as per usual inside of it with your user manager code and call ConfigureAsync from Configure but wait on it.
ConfigureAsync.ConfigureAwait(false).Wait()
ConfigureAwait (false) is used to prevent potential dead locks of waiting on the async method to complete.
Full example:
public void Configure(Seeder seeder)
{
//Edited due to typo/bad syntax.
ConfigureAsync(seeder).Wait();
}
public async Task ConfigureAsync(Seeder seeder)
{
//Now treat this like true async/await.
await seeder.Seed().ConfigureAwait(false);
}
If you run into deadlocks here, perhaps your seeder should just be synchronous? I would avoid using Task.Run() in an ASP.NET context because that will totally defeat the purpose of async/await in the first place by taking up two request threads that would have just been done on one if done synchronously.
Sometimes, you need to implement a sync interface but you only have async APIs available. There is no perfect solution.
Fortunately, this code is only called once so performance concerns don't matter. You can just do the dirty sync over async bridge:
public void ConfigureServices(IServiceCollection services)
{
ConfigureServicesImpl(services).Wait(); //bridge
}
public async Task ConfigureServicesImpl(IServiceCollection services)
{
await ...;
}
You might need to insert a deadlock protection such as ConfigureAwait(false) or Task.Run(() => ...).Wait().

Categories

Resources