C#

How to Register Services for Different Environments in .NET

In this article, we are going to learn how to register services for different environments in .NET.

To download the source code for this article, you can visit our GitHub repository.

Let’s start. 

Reasons to Register Services for Different Environments

Let’s assume we have multiple environments for different purposes: development, and production. In each environment, our application behaves differently.

For example, in a different environment, our application connects to a different database and different file storage. Moreover, if we have a live external service we wouldn’t want to use that live external service in a non-production environment, therefore, we make a dummy service to be used in a development environment. Of course, there are many more reasons to register services for different environments in our .NET application, but we get the point here.

How to Register Services for Different Environments?

Now, let’s see how to register services for different environments using a WebAPI project example.

First, let’s modify the launchSettings.json file and add two profiles for launching the application:

{
  "profiles": {
    "Development": {
      "commandName": "Project",
      "launchBrowser": true,
      "launchUrl": "Product/GetAll",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      },
      "applicationUrl": "https://localhost:7081;http://localhost:5081"
    },

    "Production": {
      "commandName": "Project",
      "launchBrowser": true,
      "launchUrl": "Product/GetAll",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Production"
      },
      "applicationUrl": "https://localhost:7081;http://localhost:5081"
    }
  }
}

The first profile we have is already the default profile in launchSettings.json, it refers to running the application in the development environment, we make a simple change inside the profile, in the "route" key and we give it the "Product/GetAll" value, so when the application runs, it directly calls the GetAll action from the Product controller.

The second profile defines the production environment. We change the profile key to "Production", and inside that profile object, we add Production as the value for the "ASPNETCORE_ENVIRONMENT" key. Moreover, we change the profile route to Product/GetAll, which maps to the GetAll action inside the Product controller.

So let’s see what is inside that controller:

[Route("[Controller]")]
public class ProductController : ControllerBase
{
    private readonly IProductService _productService;

    public ProductController(IProductService productService)
    {
        _productService = productService;
    }

    [HttpGet("GetAll")]
    public IActionResult GetAll()
    {
        var products = _productService.GetAll();
        return Ok(products);
    }
}

Now let’s take a look at IProductService interface:

public interface IProductService
{
    public List<Product> GetAll(); 
}

With this interface in place, we can create two service classes that implement IProductService, one for the development environment, and the second for the production environment.

Let’s name the first one ProductDevelopmentService:

public class ProductDevelopmentService : IProductService
{
    private readonly List<Product> _products = new()
    {
        new Product { Name = "Dev. Product 1", Id = 1 },
        new Product { Name = "Dev. Product 2", Id = 2 },
        new Product { Name = "Dev. Product 3", Id = 3 }
    };

    public List<Product> GetAll()
    {
        return _products;
    }
}

And, let’s create the second one – ProductLiveService to run in a production environment:

public class ProductLiveService : IProductService
{
    private readonly List<Product> _products = new()
    {
        new Product { Name = "Live Product 1", Id = 1 },
        new Product { Name = "Live Product 2", Id = 2 },
        new Product { Name = "Live Product 3", Id = 3 }
    };

    public List<Product> GetAll()
    {
        return _products;
    }
}

We can notice that both services implement IProductService  interface, but return different lists. 

Our goal here is, when the application runs in the development environment, to get the products from ProductDevelopmentService. Furthermore, when we run our app in a production environment, we want to get the products from ProductLiveService .

To achieve this, we have to modify the Program.cs file in our project:

using RegisterServicesForEnvironments.Services;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();

if(builder.Environment.IsDevelopment())
{
    builder.Services.AddScoped<IProductService, ProductDevelopmentService>();
}
else if (builder.Environment.IsProduction())
{
    builder.Services.AddScoped<IProductService, ProductLiveService>();
}

With the builder variable of the WebApplicationBuilder type, we have an access to the Environment property of the IWebHostEnvironment property.

With this property, we can call the IsDevelopment()method to check if the current environment is a development environment. So, if it is, we register ProductDevelopmentService to IProductService interface. 

Otherwise, we check the production environment with IsProduction(), and if it is, we register ProductLiveService to IProductService interface. 

That’s all it takes.

Now, let’s run our app in the development environment and see the result:

[
   {
      "id":1,
      "name":"Dev. Product 1"
   },
   {
      "id":2,
      "name":"Dev. Product 2"
   },
   {
      "id":3,
      "name":"Dev. Product 3"
   }
]

Right after that, we can run our app in a production environment and see a different result:

[
   {
      "id":1,
      "name":"Live Product 1"
   },
   {
      "id":2,
      "name":"Live Product 2"
   },
   {
      "id":3,
      "name":"Live Product 3"
   }
]

We get different results, which means that we successfully registered different services for different environments.

Conclusion

In this article, we’ve learned how to register services for different environments in our application.

Code Maze

View Comments

  • How does the builder know which environment it need to use (Dev vs Prod) ? Does the builder takes that profile automatically ?

      • ok, but who tells it to use "Development" env. variable ? How does it know ? you have both "Development" and "Production" env variable available in that json file.

        • Well, this depends on the profile you choose to run your app. If you run it with the development profile it will read the dev part of the launchSettings.json file. The same goes for the production profile.

Share
Published by
Code Maze

Recent Posts

HttpClient vs RestSharp – Which One to Use in .NET

HttpClient and RestSharp are HTTP Client libraries that we can use to consume APIs. Working…

Updated Date Jul 7, 2022

Testing Repository Pattern Using Entity Framework

Unit Testing is extremely important for creating robust software. It's very simple in principle but…

Updated Date Jul 6, 2022

Shell Sort in C#

Have you ever needed to sort a list of items, but didn't want to use…

Updated Date Jul 5, 2022

How to Resolve Instances With ASP.NET Core DI

In ASP.NET Core dependency injection, we usually register injectable dependencies at the start of our…

Jul 4, 2022

Ranges and Indices in C#

In this article, we are going to learn more about ranges and indices in C#,…

Updated Date Jul 2, 2022

Code Maze Weekly #128

Issue #128 of the Code Maze weekly. Check out what's new this week and enjoy…

Updated Date Jul 1, 2022