Async method that does not make async calls - c#

I need to create a method that will connect to my Azure SQL database and read some data. All the methods that call this method are async methods but I don't think I can make the ReadStateProvinceListAsync an async one.
What's the right approach in these situations? Just ignore the "warning" from the compiler that I have an async method that does not use the await keyword or make the ReadStateProvinceListAsync method a regular synchronous method in which case the GetStateProvinceListAsync method will give me the same warning.
I want to do it right -- by the book. That's why I want to learn the right approach.
public static async Task<List<StateProvince>> GetStateProvinceListAsync(string countryId)
{
// Check to see if I already have this data cached
if(gotData)
{
// Life is good! Get data from cache.
}
else
{
// Don't have the data cached. Call the DB read method
statesList = await ReadStateProvinceListAsync(countryId)
}
}
private static async Task<List<StateProvince>> ReadStateProvinceListAsync(string countryId)
{
// Call Azure SQL Database to read data. No async code here!
}

There's absolutely no value in marking a synchronous method with the async keyword. If your method doesn't make any asynchronous calls make it synchronous:
public static List<StateProvince> GetStateProvinceListAsync(string countryId)
{
// Check to see if I already have this data cached
if(gotData)
{
// Life is good! Get data from cache.
}
else
{
// Don't have the data cached. Call the DB read method
statesList = ReadStateProvinceList(countryId)
}
}
private static List<StateProvince> ReadStateProvinceList(string countryId)
{
// Call Azure SQL Database to read data. No async code here!
}
If for some reason you must return a task (e.g. it's an interface or abstract implementation) use Task.FromResult to return a Task synchronously:
private static Task<List<StateProvince>> ReadStateProvinceListAsync(string countryId)
{
return Task.FromResult(ReadStateProvinceList());
}

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.

Asynchronous operations for a repository to save new data to database

I have a class called Repository which handles a CSV file and creates Objects from parsed values.
There is are two list properties in this class:
public static List<Product> ProductsList { get; set; }
public static List<Category> CategoriesList { get; set; }
There is a method in the Repository class which parses a posted CSV file to create a list of products and categories which get assigned to ProductsList and CategoriesList respectively inside the method.
public static void CSVToList(HttpPostedFileBase CSVFile){}
Then there is another method in this class which saves the products and categories into the dbContext.Both of these methods are called from outside the Repository class in the Controller.
public static void SaveProducts()
{
foreach(var item in ProductsList)
{
db.Products.Add(item);
}
foreach(var item in CategoriesList)
{
db.Categories.Add(item);
}
await db.SaveChangesAsync();
}
When I run the application and send a post request with a CSV file, I get this error:
An asynchronous operation cannot be started at this time. Asynchronous operations may only be started within an asynchronous handler or module or during certain events in the Page lifecycle. If this exception occurred while executing a Page, ensure that the Page is marked <%# Page Async="true" %>. This exception may also indicate an attempt to call an "async void" method, which is generally unsupported within ASP.NET request processing. Instead, the asynchronous method should return a Task, and the caller should await it.
Source Error:
Line 348: {
Line 349: Repository.CSVToList(viewModel.CSVFile);
Line 350: Repository.SaveProducts();
Line 351:
Line 352: return RedirectToAction("Index", new { ManageMessageId.DataImportSuccess });
Source File: C:\src\smokindonut\Valueville\ValueVille\Controllers\ManageController.cs Line: 350
I have tried to make the controller method be an asynchronous Task with the caller to the repository save method await:
public async Task<ActionResult> AddCSVData(){
await Repository.SaveProducts();
}
I have also tried to make the SaveProducts() method be an asynchronous task also, but it keeps making the method name start with "async" - each time giving the same error.
You need to changed the signature of your function
public static void SaveProducts()
To
public async Task SaveProducts()
Your calling function then needs have a signature with async Task and call the save function like this:
Task saveTask = SaveProducts();
//do some logic
await saveTask;

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.

Async or parallel function

I am working on an application (ASP.NET MVC5) which saves a pile of data to the database in one go. The method which saves the data takes time to do it and I do not want to block user interface.
Here I have created a test program which will sleep for 10 sec and I do not want to return any result from this program.
public Task SaveFunc()
{
Thread.Sleep(10000);
return null;
}
public void ShowFunction()
{
SaveFunc();
retrun "Your request is under process";
}
Now, how do I call SaveFunc in such a way that I do not have to wait for the result.
You should use the async method Task.Delay since Thead.Sleep is synchronous and blocks the current context. You also need to return a Task from the method instead of null and await the Task to wait until it ends. In the mean time, your program can run as is:
public Task SaveFunc()
{
return Task.Delay(10000);
}
public async void ShowFunction()
{
await SaveFunc().ConfigureAwait(false);
}
This answer asumes you are using ASP.NET MVC - if this is not the case please update your question:
Since .NET 4.5.2 you can do the following:
public ActionResult ShowFunction()
{
HostingEnvironment.QueueBackgroundWorkItem(cancellationToken =>
{
// Some long-running job
});
return Content("Your request is under process");
}
If you are still on an old .NET version you can do something like:
public ActionResult ShowFunction()
{
ThreadPool.QueueUserWorkItem(c =>
{
// Some long-running job
});
return Content("Your request is under process");
}
but the execution of ThreadPool.QueueUserWorkItem can be canceled by an AppDomain-recycle so you need to take care of such scenarios. Since .NET 4.0 you can also use Task.Factory.StartNew(() => { /*...*/ }); and get a Task to work with.

Categories

Resources