📜 ⬆️ ⬇️

Asynchronous programming in ASP.NET MVC 4 applications

After reading the article about studying MVC and seeing the comment from RouR user, I was very interested in this topic, and on the move I decided to translate the original article indicated by him.

If to you, dear habrazhitel, it is interesting - I ask under kat!

“I will try to show you what's new in C # 5.0 in terms of asynchronous programming when using the await keyword. Especially for ASP.NET MVC 4 web applications. "
')

I played for a while with Visual Studio Async CTP and now I have enough thoughts on how it works and how to use it correctly. And that means I can write about it.

The main problem of most of our software is operations that require a long execution time. The user starts such an operation - and it blocks the main thread of the program until its execution ends. As a result, we get inconvenient software users and dissatisfied customers. I am sure that each of us came across such programs!

Asynchronous programming is far from a new paradigm, it was already at the time of .NET 1.0. I was not very interested in programming 3 years ago, so this concept is quite new for me and still is. As far as I read, the concept has evolved in many respects from the point of view of .NET for asynchronous programming and, it seems to me, is now at its best stage.

On the one hand, in asynchronous programming it is very easy to get confused, as it has already happened to me several times. I went back and forth and thought a lot about how this thing works and where to apply it. And I want to believe that in the end I understood everything correctly. On the other hand, it is even easier to get confused in asynchronous programming, if you use it in web applications, because we do not have a UI thread into which we could immediately output the work. Asynchronously or not, the user must wait some time. That is why asynchronous programming is undesirable for web applications. And if you think so too (and I myself thought so before), it means you have not understood anything yet!

If your operation is performed synchronously and takes a lot of time, then you have no choice but to block the main thread until its completion. And if you do the same operation asynchronously, it means that you start the operation and continue to do something, returning to the results of your operation only when it is already completed. Between the start and the end of the operation, your thread is free and can do other things. I think that most people are confused here. Creating additional streams is expensive and can lead to problems, but it seems to me that this is already in the past. In .NET 4.0, we have dramatically increased the limit on the number of threads launched, but this does not mean that you need to create a lot of threads everywhere and everywhere - at least now you shouldn’t worry when creating the next thread. Now there are (or should I say, already gone?) A lot of controversy about asynchronous programming:


I do not know the exact answer to all these questions, but here are a couple of examples:


Now, as they say, it’s time for us to take advantage of asynchrony in one form or another. So what's the problem? And the problem is how this asynchronous model works. As Anders Hejlsberg says, this software model turns our code inside out. Not to mention how difficult it is to make nested calls to asynchronous operations with exception handling.

Visual Studio Async CTP and how it works


In C # 5.0, we will have a new model of asynchronous programming, very similar to the synchronous one. In the meantime, the developers have released CTP for the current version, which is available under the Go-Live license. Here is a quote from the AsyncCTP specification:

" Asynchronous functions - a new feature in C # that makes it easy to describe asynchronous calls. When the function reaches the expression with the await keyword and its execution begins, the rest of the function will be rebuilt, as the automatic continuation of the operation will be performed, and while the function itself will continue to be executed. In other words, the language itself, not the programmer, now takes the task of building the order in which the code is executed. chrono code acquires a logical structure. "

An asynchronous function is a class method or an anonymous function marked with the async modifier. It can return both an object of class Task , and Task <T> for an arbitrary type T — such functions can have await . If the function marked async returns void (which is also valid), then it will not be possible to use await . But on the other hand, we can use any type as T.

ASP.NET MVC 4 and C # Asynchronous Features


Proper use of asynchrony in ASP.NET MVC applications can have a very positive impact on performance. Believe it or not, it is. Now I will show you how.

So why aren't we everywhere and doing everything asynchronously? And because it is very hard, fraught with errors and ultimately difficult to maintain our application later. But with the new asynchronous model, this will soon change.

In ASP.NET MVC 4, asynchronous programming has changed a lot. Perhaps you know that in ASP.NET MVC 3 our controller should be inherited from AsyncController and should match a specific pattern. You can read about this in the article " Using asynchronous controllers in ASP.NET MVC ".

In ASP.NET MVC 4, we no longer need to use AsyncController, it’s enough to mark our controller with the async keyword and return an object of the Task or Task <T> class (where T is usually an ActionResult ).

I tried to combine two examples in one application that do the same action - synchronously and asynchronously, respectively. And also I conducted load testing, and the results shocked me! Now let's take a look at the code.

First, I created the simplest REST service using the new ASP.NET Web API . The simplest model that stores the collection in memory (you could use the database instead):
public class Car { public string Make; public string Model; public int Year; public int Doors; public string Colour; public float Price; public int Mileage; } public class CarService { public List<Car> GetCars() { List<Car> Cars = new List<Car> { new Car { Make="Audi", Model="A4", Year=1995, Doors=4, Colour="Red", Price=2995f, Mileage=122458 }, new Car { Make="Ford", Model="Focus", Year=2002, Doors=5, Colour="Black", Price=3250f, Mileage=68500 }, new Car { Make="BMW", Model="5 Series", Year=2006, Doors=4, Colour="Grey", Price=24950f, Mileage=19500 } //This keeps going like that }; return Cars; } } 

And the service code:
 public class CarsController : ApiController { public IEnumerable<Car> Get() { var service = new CarService(); return service.GetCars(); } } 

So, I have a service. Now I will write a web application that will receive data from the service and show it. For this, I wrote a class of service that receives data and deserializes them: for asynchronous calls, I used the new HttpClient , and for synchronous calls , the familiar WebClient . I also used Json.NET :
 public class CarRESTService { readonly string uri = "http://localhost:2236/api/cars"; public List<Car> GetCars() { using (WebClient webClient = new WebClient()) { return JsonConvert.DeserializeObject<List<Car>> ( webClient.DownloadString(uri) ); } } public async Task<List<Car>> GetCarsAsync() { using (HttpClient httpClient = new HttpClient()) { return JsonConvert.DeserializeObject<List<Car>> ( await httpClient.GetStringAsync(uri) ); } } } 

About the method GetCars nothing to say - it is simple. But about GetCarsAsync, you can say the following:


And finally, here it is the controller:
 public class HomeController : Controller { private CarRESTService service = new CarRESTService(); public async Task<ActionResult> Index() { return View("index", await service.GetCarsAsync()); } public ActionResult IndexSync() { return View("index", service.GetCars()); } } 


So, we have Index - an asynchronous function that returns Task <ActionResult> , and IndexSync - a normal synchronous call. If we go to the address / home / index or / home / indexsync , we will not see much difference in the speed of opening pages - it is about the same.

To measure the difference in the performance of these methods, I created load tests in MS Visual Studio 2010 Ultimate. Within two minutes I will open these two pages, starting with a load of 50 users, gradually increasing it to 20 users every 5 seconds. The maximum limit is 500 users. See the result (clickable):

image

It can be seen that for the synchronous variant the response time is 11.2 seconds, and for the asynchronous one it is 3.65 seconds. I think the difference is obvious.

From that moment on, I became an adherent of the concept “Everything that takes longer than 40ms (operations related to the network, file system — that is, all the main I / O) —all this should be asynchronous!”

Source: https://habr.com/ru/post/142372/


All Articles