My C# REST run now 250 times faster
Tags: api, csharp, dotnet, programming
Published: 2023-05-29 08:33:49

## Intro

This article is about how to make you API work really faster (**_i've got 250 times faster_**) using [our library](https://github.com/Wissance/WebApiToolkit), we are going to show it with [our well-known example of Weather Control REST API](https://github.com/Wissance/WeatherControl). But in particular, we consider `Create` and `Update` operations of a standard `CRUD` controls. We made previously mentioned library **_to reduce amount of code and make a result of the same wrapping DTO_ (standartize the data contract)**. Today, **_we need just only < 10 lines_** of code **_to create any controller_** with **_all standard CRUD_** methods.

## How we could speed up REST API
We could make API to perform faster if we are going to **_create/update multiple objects at once_** (_bulk api_), sometimes it is possible and _could be crucial to achieve a higher performance_. In the mentioned above example, we are using Controller class with Bulk Api (derives from [`BasicBulkCrudController`](https://github.com/Wissance/WebApiToolkit)) could be easily created as follows:
```csharp
namespace Wissance.WeatherControl.WebApi.Controllers
{
    public class MeasurementsSeriesController: BasicBulkCrudController<MeasurementsDto, MeasurementsEntity, int>
    {
        public MeasurementsSeriesController(MeasurementsManager manager)
        {
            Manager = manager;  // this is for basic operations
            _manager = manager; // this for extended operations
        }

        private MeasurementsManager _manager;
    }
}
```
This code automatically contains 4 mehods:

* `GET /api/MeasurementsSeries` for getting multiple measurements with paging
* `GET /api/MeasurementsSeries/{id}` to get one measurements by id
* `POST /api/bulk/MeasurementsSeries` for creating multiple objects (bulk API);
* `PUT /api/bulk/MeasurementsSeries` for updating multiple objects (bulk API);
* `DELETE /api/bulk/MeasurementsSeries/{idList}` for removing multiple object (bulk API), could be called like `~/api/bulk/MeasurementsSeries/id=1&id=2&id=5`
A full example of Manager class with all bulk operations [you could see here](https://github.com/Wissance/WeatherControl/blob/master/WeatherControl/Wissance.WeatherControl/Managers/MeasurementsManager.cs). Here i show non-optimal but working example with EntityFramework, even this impl make my code working 250 times faster for creating 10 items (see performance check below method code). So i just add array of MeasurementsEntity and add them to DbSet and after all **_make one Save instead of multiple for each object_**:
```csharp
public override async Task<OperationResultDto<MeasurementsDto[]>> BulkCreateAsync(MeasurementsDto[] data)
        {
            try
            {
                IList<MeasurementsEntity> measurements = data.Select(d => MeasurementsFactory.Create(d)).ToList();
                await _modelContext.Measurements.AddRangeAsync(measurements);
                int result = await _modelContext.SaveChangesAsync();
                if (result >= 0)
                {
                    return new OperationResultDto<MeasurementsDto[]>(true, (int)HttpStatusCode.Created, null,
                        measurements.Select(m => MeasurementsFactory.Create(m)).ToArray());
                }
                return new OperationResultDto<MeasurementsDto[]>(false, (int)HttpStatusCode.InternalServerError, "An unknown error occurred during measurements creation", null);
            }
            catch (Exception e)
            {
                return new OperationResultDto<MeasurementsDto[]>(false, (int)HttpStatusCode.InternalServerError,
                    $"An error occurred during measurements update: {e.Message}", null);
            }
        }
```
Because **we claim that we made our API working faster**, let’s **_check performance using Python_**. For a very rough view we made comparison of time elapse for query single bulk endpoint vs sequential call of non-bulk endpoint (worst case) for POST new items as a result **_we’got ~250x time performance raise_** (see Python test [here](https://github.com/Wissance/WeatherControl/blob/master/perfTests/bulk_api_tests/api_perf_test.py)), see picture below

![Performance Bulk VS Non-bulk comparison](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tdnw0ln5cu956uydqmml.png)

I wrote simple tests using Python that shows following results:
```
Elapsed time in Non-Bulk REST API with EF is 0.9759984016418457 secs.
Elapsed time in Bulk API with EF is 0.004002094268798828 secs.
```
So just using such a simple technique we made API working faster in a better case (for non-bulk API example) all request could be made parallel in time, but this isn’t solving bottleneck issue with persistence manager (EntityFramework in this current case).

## Conclusion
Therefore, we could conclude that REST resources that allow to use bulk operations could be made working faster, and we have prepared boilerplate reusable solution (Wissance.WebApiToolkit). We would be very appreciated if you could [give us a star on Github](https://github.com/Wissance/WebApiToolkit).