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. 

Support Code Maze on Patreon to get rid of ads and get the best discounts on our products!
Become a patron at Patreon!

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.

Liked it? Take a second to support Code Maze on Patreon and get the ad free reading experience!
Become a patron at Patreon!