ASP.NET core & C#. How to run a synchronous method asynchronously - asp.net-core

My ASP.NET core application uses Entity Framework Core. As you would expect must controller methods are async and call async methods of EF Core.
I also have controller methods thats need to read from and write to excel files. I'm using OpenXml. Since these are IO operation, ideally I they would be an async operation but OpenXml doesn't offer any async methods. Here is a simplified example
private async Task<model> ReadFromExcel()
{
using var document = SpreadsheetDocument.Open("filePathAndName", false);
// read data into model
document.Close();
context.Models.Add(newModel);
await Context.SaveAsync();
return newModel;
}
Also, I need to find the file in a folder first which I would also like to make async.
Directory.EnumerateFiles("excelFolderName", ".xlsx");
According to this document ASP.NET Core Performance Best Practices I shouldn't use Task.Run to make an synchronous API asynchronous. I understand why but does that rule apply to IO operations which will block the thread potential for a few seconds? Should I make these IO operations async and if so what is the base way to make reading and writing excel file and getting file list asynchronous?

Since these are IO operation, ideally I they would be an async operation but OpenXml doesn't offer any async methods.
Also, I need to find the file in a folder first which I would also like to make async.
Ideally, those would be asynchronous APIs. But they're not. The way to make them asynchronous is to fix the API, not wrap it in Task.Run. You can open a request with the maintainers of OpenXml for asynchronous APIs. The file system operation is more awkward; it's a Win32 limitation, not a BCL limitation, and it's unlikely to be fixed, but you can ask.
does that rule apply to IO operations which will block the thread potential for a few seconds?
Yes.
The request is blocked for the same amount of time whether it's synchronous or asynchronous. So the thing to consider is how threads are blocked. In the ideal asynchronous case, no threads are blocked. Since you only have synchronous APIs, you do have to block a thread; calling the API directly will block a thread pool thread, and shoving it off to Task.Run will block a different thread pool thread - which is pointless.
Should I make these IO operations async and if so what is the base way to make reading and writing excel file and getting file list asynchronous?
You can't "make them async". You can request async APIs and then use the synchronous ones for now.

Related

Should async controlles always used in MVC for data access

ERP+Shopping cart ASP.NET MVC 4.8 application is planned to migrate to .NET 5 MVC Core application.
Entity Framework Core with NpgSql data provider is planned to use.
MVC 4.8 application does no use any async method.
There are async methods in .NET 5 for Data Accesss like ToListAsync(), ExecuteSqlInterpolatedAsync().
Samples of Core MVC Controllers return async tasks like
[HttpPost]
public async Task<IActionResult> LogOn(LogOnModel model, string returnUrl,
[FromServices] ShoppingCart shoppingcart
)
There will be 100 human users.
Application has also Web API providing json data over http. Shopping cart part allows anonynous access an is scanned by search engines.
Ngpsql has connation pooling support so multiple connections are added automatically.
Application is hosted in Debian Linux VPS server with 4 Cores using Apache.
VSP has 20 GB of RAM so lot of data is cached by Linux. However probably most of time is still consumed by reading data from Postgres database.
Most controllers read and write data to/from database.
Answer in
https://forums.asp.net/t/2136711.aspx?Should+I+always+prefer+async+actions+over+sync+actions+
recommends to use async methods for data access always.
Answer in
Always using Async in an ASP.NET MVC Controller
recommends not to use async always.
Conclusion from https://gokhansengun.com/asp-net-mvc-and-web-api-comparison-of-async-or-sync-actions/ states
However async actions do not come with zero cost, writing async code
requires more care, proficiency and it has its own challenges.
Application and Database in in same VPS server
Answer in
mvc should everything be async
states that async should not used if application and database are in same server.
Answer in
When should I use Async Controllers in ASP.NET MVC?
states
I'd say it's good to use it everywhere you're doing I/O.
but afterwards:
If you're talking about ASP.NET MVC with a single database backend,
then you're (almost certainly) not going to get any scalability
benefit from async. This is because IIS can handle far more concurrent
requests than a single instance of SQL server (or other classic RDBMS)
There two upgrade paths in my case:
Continue to use only sync methods. Don't waste resources on async. Existing tested MVC controllers code can used. Number of threads in kestrel is not limited. Assume in future .NET compiler creates async code by analyzing application and manual async will become obsolete.
Change MVC controllers signatures to
public async Task
Replace all EF data access calls with async calls. Assume this is solid .NET feature which remains. Re-factor code so that Visual Studio 2019 warnings will not appear after change. After my application is released this allows to optimize existing code without major re-write.
Which upgrade path should used in this case ?
Will changing everything to async introduce new bugs in code ?
Async is not mandatory for web applications. It is mostly mandatory for GUIs only.
Your application will continue to work. Async programming is great at handling scale of requests. But you said you have at most 100 users. If they were 100.000, your application would have suffered a lot.
And I can tell for sure that async programming does come with challenges, because for example there are issues with transactions if you don't handle it properly.
Of course threads come with a cost too. Async exists to avoid the 500KB of overhead that is required for every thread. This means that the machine(s) running the application might need to be scaled vertically. In this sense, async saves RAM.
The choice is yours. Since you are refactoring your app anyways, you could work on improving it to the next step and get it ready for bigger scale.
Otherwise your application will still work fine for 100 users.
[Edit] a pull request is worth 1000 words. In async context, the transaction should be initialized with TransactionScopeAsyncFlowOption.Enabled to avoid the exception descripted and in order to tell the transaction engine that the thread is participating an async flow. To keep it simply simple, async flows share the same thread, so application code (and transaction management is C# code) must not rely on thread-local information and has to clean up context every time the context is switched to another async flow asking for attention.
Conclusion: your first comment is correct. Async flows dramatically reduce RAM utilizations on concurrent requests.

WCF Web Service and TPL Task.Run

Suppose I have a method, which does not require a response, for example:
[ServiceContract]
public interface IWCFTestService
{
[OperationContract]
void ReceiveSomeData(MyDto someDtoObj);
}
Now, inside the actual service implementation, I can write:
public void ReceiveSomeData(MyDto receivedRequest)
{
Task.Run( () => OtherProjectOtherClass.DoWhateverYouWant(receivedRequest) )
//... because I am outta here as fast as possible
}
I assume the caller will get a 200-OK all the time; Note also that I have not written any task async/await inside the WCF method itself.
Is it acceptable to use TPL inside WCF this way, any gotchas?
Note: I am not concerned with business rules, I am more concerned whether it is technically acceptable for WCF/TPL to interact this way, will I run into (technical) trouble?
There are a couple of things that you have to take in consideration.
Callers won't be notitified when the task is actually completed, and if it does, whether it did so with a failure (an unhandled exception for example) or not.
When the process hosting the service stops, your tasks may not be completed yet and unless you keep a reference to them you won't be able to wait for them to finish.
If an unhandled exception occurs in OtherProjectOtherClass.DoWhateverYouWant(receivedRequest) you won't be signalled. So make sure the whole body is contained in a try..catch and apply some logging or take other measures.
If a lot of requests are made and the tasks take a long time to complete you can run out of threads in the threadpool. If so, use a dedicated thread as Task.Run grabs one from the pool.
I do wonder, what is happening inside OtherProjectOtherClass.DoWhateverYouWant(receivedRequest)? Is it CPU intensive or more I/O related? If it is I/O intensive, rewrite it to a Task based method instead of using Task.Run.
I can't tell if these issues are really problems for you but keep it in mind.

Extending WCF with async code

How do we integrate custom async code in the WCF pipeline, either with await/async or IAsyncResult?
Basically I'm considering the possibility of doing possibly blocking operations during message processing. Two areas for now:
Logging, where we may want to write to a file / database that exposes async versions (granted, this could be done with a queue and a writer thread)
Authorization, where we may need to query a database and it also provides async methods.
Now I was looking on the WCF extensibility points and I can't find any hooks with async versions. I'm looking for IParameterInspector, IDispatchMessageInspector and the likes.
Even the new ClaimsAuthorizationManager doesn't seem to provide an async counterpart either.
I feel I'm missing some big part of the puzzle here, because I have this project where all the code uses the new async features and now I can't hook it up here without doing a .Wait() call on the Tasks.
Could someone shed some lights here or tell me what's wrong with this?
I believe WCF (like MVC) only supports async at the operation level (for now); the pipeline is not fully async. On the other hand, WebAPI was designed with async in mind and supports it at all stages in its pipeline.

Asynchronous WCF

I am trying to create a WCF service that supports asynchronous calls. I followed all samples and tutorials I could find, and all of them have the customary pattern of one synchronous method, and the async Begin and End such as:
[OperationContract(AsyncPattern = false)]
string GetData(int value);
[OperationContract(AsyncPattern = true)]
IAsyncResult BeginGetData(int value, AsyncCallback callback, object asyncState);
string EndGetData(IAsyncResult result);
However, only the synchronous GetData gets called, no matter what I do on the client side. Fiddler tells me that the message is always the same:
<s:Envelope
xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Body><GetData
xmlns="http://tempuri.org/"><value>0</value></GetData></s:Body></s:Envelope>
When I remove the synchronous GetData interface, the async method now is properly called.
Is this normal behavior? Is there anything else I should do to support sync and async versions of a method?
This is a common misconception. You assume that you need to make the server asynchronous in order for the client to be able to make async calls. This is not true. Server and client are 100% independent. They are separated by a binary wire protocol.
The message that you see in Fiddler is always the same because SOAP does not know anything about sync or async. At the SOAP level your decision does not manifest itself. For that reason the client cannot observe your server-side decision, either.
This means you can just make the server synchronous in still have a truely async client, or the other way around.
In any case, you should only implement one pattern on the server: Either sync or async. Never both. Get rid of one of your implementations. From a functional standpoint it doesn't matter which one stays.
I'm pulling up important information from the comments here:
It is hard to fit an explanation about when to use server-side async
into this comment box. In short, don't use it on the server by
default. Use it if special circumstances make it attractive or
necessary.
On a meta-level let me point out that async IO has become
a fad that should not be followed lightly. The community is in a very
unfortunate state of misinformation about this right now.

Asynchronous DAO in Flex / Sqlite?

The article gives a good insight of how to deal with sqlite in Flex; but it doesn't get deep into how to tackle asynchronous data access.
For example, if I have an EmployeesDAO that does the followings:
updateEmployee(emp:Employee):void
findEmployee(emp:Employee):void
findAllEmployees():ICollectionView
etc..
As long as the EmployeesDAO implements asynchronous mode these methods are only legitimate after the db is connected and the tables are created. The client has to know about this asynchronous nature in order to use these methods as the following will throw an SQLErrorOperation as findAllEmployees will attempt to execute a "SELECT" operation before the db is connected:
var dao:IEmployeesDAO = new EmployeesDAO();
var employees:ArrayCollection = dao.findAllEmployees();
What is the best practice to deal with instantiation of the asynchronous DAO? Is it possible to hide the asynchronous nature from the client of the data access objects (i.e., the client isn't aware whether it's using sync or asynchronous DAOs)?
The only way I know to tackle a problem like that is to use pass the results to a callback. That's how we tackled listening to various async tokens or event messages.
What you are asking is not possible in the flash universe to my knowledge. In JS I know of only one project that effectively tackles this problem.
http://stratifiedjs.org tries to be javascript-like language with just some extra keywords to decide what you want to do in asynchronous situations and compiles to not-so-readeable but very performant JS behind the scenes.
Have a look: http://elromdesign.com/blog/2009/01/18/adobe-air-sqlite-manager-help-you-handle-your-database-easily/
There is a fundamental difference between asynchronous and sync programming and the client code has to be aware of that to use the service. The pattern for dealing with asynchronous database connectivity is to have the client pass callbacks to a specific operation invocation to handle the result (if successful) or fault (if operation failed). The callbacks can be encapsulated in things such as flash.net.Responder or mx.rpc.IResponder, etc.. In a LOB application, the life-cycle of the app is tied to the DB connectivity such that the moment the app attempts to start, DB connection has to either already be established (such as user being authenticated) or otherwise the UI locks the user out. After the DB connection has been established, all the DAO instances can get hold of the DB connection. Of course the subsequent operations on the DB still need to implement the callback patterns mentioned above.