In this article, we are going to learn how to register services for different environments in .NET.
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.
How does the builder know which environment it need to use (Dev vs Prod) ? Does the builder takes that profile automatically ?
It reads from the ASPNETCORE_ENVIRONMENT variable.
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.
I see. got it. thank you!