DEV Community

Cover image for My C# REST run now 250 times faster
Ushakov Michael for Wissance

Posted on • Edited on

My C# REST run now 250 times faster

Intro

This article is about how to make you API work really faster (i've got 250 times faster) using our library, we are going to show it with our well-known example of Weather Control REST API. 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) could be easily created as follows:

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;
    }
}
Enter fullscreen mode Exit fullscreen mode

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. 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:
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);
            }
        }
Enter fullscreen mode Exit fullscreen mode

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), see picture below

Performance Bulk VS Non-bulk comparison

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.
Enter fullscreen mode Exit fullscreen mode

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.

Top comments (0)