.Net Core 3.0 API Best Practices

Praveen Sambu
5 min readFeb 28, 2020

--

I would share some of the best practices we can follow in our .Net core project. We are going to write about what we consider to be the best practices while developing the .NET Core Web API project. How we can make it better and how to make it more maintainable.

STARTUP CLASS AND THE SERVICE CONFIGURATION

In the Startup class, there are two methods: the ConfigureServices method for registering the services and the Configure method for adding the middleware components to the application’s pipeline.

So, the best practice is to keep the ConfigureServices method clean and readable as much as possible. Of course, we need to write the code insidethat method to register the services, but we can do that in more readable and maintainable way by using the Extension methods.

For example, let’s look at the wrong way to register CORS:

Even though this way will work just fine, and will register CORS without any problem, imagine the size of this method after registering dozens of services.

That’s not readable at all.

The better way is to create an extension class with the static method:

And then just to call this extended method upon the IServiceCollection type:

PROJECT ORGANIZATION

We should always try to split our application into smaller projects. That way we are getting the best project organization and separation of concerns (SoC). The business logic related to our entities, contracts, accessing the database, logging messages or sending an email message should always be in a separate .NET Core Class Library project.

Every small project inside our application should contain a number of folders to organize the business logic.

ENVIRONMENT BASED SETTINGS

While we develop our application, that application is in the development environment. But as soon as we publish our application it is going to be in the production environment. Therefore having a separate configuration for each environment is always a good practice.

In .NET Core, this is very easy to accomplish.

As soon as we create the project, we are going to get the appsettings.json file and when we expand it we are going to see the appsetings.Development.json file:

All the settings inside this file are going to be used for the development environment.

We should add another file appsettings.Production.json, to use it in a production environment:

DATA ACCESS LAYER

In many examples and different tutorials, we may see the DAL implemented inside the main project and instantiated in every controller. This is something we shouldn’t do. When we work with DAL we should always create it as a separate service. This is very important in the .NET Core project because when we have DAL as a separate service we can register it inside the IOC (Inversion of Control) container. The IOC is the .NET Core’s built-in feature and by registering a DAL as a service inside the IOC we are able to use it in any controller by simple constructor injection:

The repository logic should always be based on interfaces and generic as well.

CONTROLLERS

CONTROLLERS

The controllers should always be as clean as possible. We shouldn’t place any business logic inside it. So, our controllers should be responsible for accepting the service instances through the constructor injection and for organizing HTTP action methods (GET, POST, PUT, DELETE, PATCH…): public class OwnerController:

ACTIONS

Our actions should always be clean and simple. Their responsibilities include handling HTTP requests, validating models, catching errors and returning responses:

The most used methods are:

OK => returns the 200 status code

NotFound => returns the 404 status code

BadRequest => returns the 400 status code

NoContent => returns the 204 status code

Created, CreatedAtRoute, CreatedAtAction => returns the 201 status code Unauthorized => returns the 401 status code

Forbid => returns the 403 status code

StatusCode => returns the status code we provide as input

HANDLING ERRORS GLOBALLY

In the example above, our action has its own try-catch block. This is very important because we need to handle all the errors (that in another way would be unhandled) in our action method. Many developers are using try catch blocks in their actions and there is absolutely nothing wrong with that approach. But, we want our actions to be clean and simple, therefore, removing try-catch blocks from our actions and placing them in one centralized place would be an even better approach.

.NET Core gives us an opportunity to implement exception handling globally with a little effort by using built-in and ready to use middleware. All we have to do is to add that middleware in the Startup class by modifying the Configure method:

USING ACTION FILTERS TO REMOVE DUPLICATED CODE

Filters in ASP.NET Core allows us to run some code prior to or after the specific stage in a request pipeline. Therefore, we can use them to execute validation actions that we need to repeat in our action methods.

We can create our filter:

And register it in the Startup class in the ConfigureServices method:

services.AddScoped<ModelValidationAttribute>();

Now, we can use that filter with our action methods.

ROUTING

In the .NET Core Web API projects, we should use Attribute Routing instead of Conventional Routing. That’s because Attribute Routing helps us match the route parameter names with the actual parameters inside the action methods. Another reason is the description of the route parameters. It is more readable when we see the parameter with the name “ownerId” than just “id”.

A few wrong examples:

Writing them correctly

I would not stop here… I would try to learn more and come with another article.

--

--

Praveen Sambu
Praveen Sambu

Written by Praveen Sambu

Software Engineer |AWS Community Builder |Technical Blogger | Trainer . Founder of Cloud In Detail (https://cloudindetail.com/) still working on building blog…

No responses yet