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.
Related
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.
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.
I am constructing a web service that receives data and updates it periodically. When a user pings the service, it will send specific data back to the user. In order to receive this data, I have a persistent that is created on startup and regularly receives updates, but not at periodic intervals. I have already implemented it, but I would like to add DI and make it into a service. Can this type of problem be solved with a BackgroundService or is this not recommended? Is there anything better I should use? I originally wanted to just register my connection object as a singleton, but since singletons are not initialized on startup, that does not work so well for me.
I thought I would add an answer as so expand on my comment. From what you have described, creating a BackgroundService is likely the best solution for what you want to do.
ASP.NET Core provides an IHostedService interface that can be used to implement a background task or service, in your web app. They also provide a BackgroundService class that implements IHostedService and provides a base class for implementing long running background services. These background services are registered within the CreateWebHostBuilder method in Program.cs.
You can consume services from the dependency injection container but you will have to properly manage their scopes when using them. You can decide how to manage your BackgroundService classes in order to fit your needs. It does take an understanding of how to work with Task objects and executing, queueing, monitoring them etc. So I'd recommend giving the docs a thorough read, so you don't end up impacting performance or resource usage.
I also tend to use Autofac as my DI container rather than the built in Microsoft container, since Autofac provides more features for resolving services and managing scopes. So it's worth considering if you find yourself hitting a wall because of the built in container.
Here's the link to the docs section covering this in much more depth. I believe you can also create standalone service workers now, so that might be worth a look depending on use case.
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services?view=aspnetcore-3.1&tabs=visual-studio
Edit: Here's another link to a guide an example implementation for a microservice background service. It goes a little more in depth on some of the specifics.
https://learn.microsoft.com/en-us/dotnet/architecture/microservices/multi-container-microservice-net-applications/background-tasks-with-ihostedservice#implementing-ihostedservice-with-a-custom-hosted-service-class-deriving-from-the-backgroundservice-base-class
IStartupFilter is the basis of a mechanism for libraries to add middleware to the app. According to the Docs "IStartupFilter is useful to ensure that a middleware runs before or after middleware added by libraries at the start or end of the app's request processing pipeline".
Does the mechanism allow you to manipulate the pipeline in any way that can't be done from Startup.Configure()?
If the point is modularity then you just seem to be trading coupling through Startup.Configure() for coupling via the IServicesCollection (a call to DI is required). In the simple case (as per the example) a call to services.AddTransient<IStartupFilter, ...>() can be removed from ConfigureServices() and app.AddMiddleware<MyMiddleware>() can be added to achieve the same functionality with less complexity and magic.
Is the main point of the mechanism to allow the library to apply conditions as to what middleware should be included? If so, it seems to lack asp.net core's customary economy and clarity of design.
In the simple case (as per the example) a call to services.AddTransient<IStartupFilter, ...>() can be removed from ConfigureServices() and app.AddMiddleware() can be added to achieve the same functionality with less complexity and magic.
That's not true.
There is a big difference between using IStartupFilter and using a middleware. A middleware is part of the request pipeline, which means it gets executed on every request. On the other hand, IStartupFilter gets executed just once when the application starts (not on every request).
To answer my own question, I think that the main use case is to enable the framework to encorporate assemblies that were not known at build time. The docs cover this in the aspnetcore/Fundamentals/Host nhance an app from an external assembly in ASP.NET Core with IHostingStartup. (Although the documentation makes no mention of IStartupFilter the associated StartupDiagnostics sample project does.
IStartupFilter is usually used when you do not want any intervention from app’s author i.e. you don’t want that app.Usexxxx() to get called but a different component should configure that middleware. Now, consider a scenario where you want to execute certain code even if the request pipeline is not executed.
Lets take a URI which does not exist and returns 404 error, in that case request processing pipeline won’t be executed but startup filter will be.
A simple answer is no, it doesn't add any new functionality.
The point behind the IStartupFilter is to run some stuff in the pre-defined order independently on how yours Startup.Configure method changes. It simply creates a sequence of methods they do actions on IApplicationBuilder (WebHostBuilder) to build the middleware pipeline. You can define action that will perform before or after the Startup.Configure method is called.
Your IStartupFilter implementation will look similarly to this:
public class ExampleStartupFilter : IStartupFilter
{
public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
{
return builder =>
{
// This will run before the Startup.Configure
builder.UseMiddleware<PreStartupConfigureRegisteredMiddleware>();
// This is Startup.Configure (or the next IStartupFilter.Configure in the sequence)
next(builder);
// This will run after Startup.Configure
builder.UseMiddleware<AfterStartupConfigureRegisteredMiddleware>();
};
}
}
Arguably, as you have to register your IStartupFilter in the Startup.ConfigureServices method and the order the filters are registered is the order they will be performed, there is not much difference compare to the order of direct registrations of UseMiddleware in Startup.Configure.
The only benefit I can see is that you can register something that has absolutely run the first or the last in the pipeline, no matter what other middlewares you use. Then you don't have to worry about changes in the Configure method. It should, however, be used very scarcely.
Very good blog post explaining how the IStartupFilter works has been written by Andrew Lock, check it out here:
https://andrewlock.net/exploring-istartupfilter-in-asp-net-core/
One thing Andrew points out is that you can register filter to run it prior to the AutoRequestServicesStartupFilter registered automatically by the WebHostBuilder. Not that I would be aware of an example where this would have a practical use.
I am trying to use asyn CTP with WCF, but I have problems because Task is not serializable.
I have installed CTP v3.
Is it possible to use asyn CTP with WCF? is it need to configure something more than install only the CTP?
I am thinking that if is not possible to use async CTP jet, perhaps instead of using async CTP in the service side, I can implement async method with async CTP that call to the normal methods (not async methods) of the service. is this a good option? In this case the service does not implement async methods.
Other option is in the service side, implement the async methods with the begin/end methods, wrapping this two methods in a task using Task.Factory.FromAsync method. But this is more work.
So My question is, if I want that the client is not blocked while it waits for the service response, I can use two solutions. First use async CTP in the client that call normal methods of the service, or use async methods in the service using Task.Factory.FromAsync. Which is the best option? Why?
Thanks.
Daimroc.
I'm not sure about VS 2010 with Async CTP, but with VS 11 Beta (which you should probably use anyway), you can simply define an operation that returns a Task:
[OperationContract]
Task<string> GetData(int value);
And then implement it using async:
public async Task<string> GetData(int value)
{
return await …;
}
I would assume the same approach would work with Async CTP, but it's just an assumption.
The simplest way to achieve a non-blocking client call is on the client side, for two reasons:
Client side asynchronous methods can be generated by the existing VS tools
Passing Task over service boundary would require you write your own synchronization functionality.
To generate client-side Task<> based (and therefore async/await compatible) methods for a service:
In VS11, a new checkbox exists: "Generate Task-based methods" under "Allow generation of asynchronous operations" in the Configure Service Reference dialog. (I believe it is not yet documented)
For the CTP you can use the extension described here to generate Task based methods.