Skip to content

Commit

Permalink
Added a new section to explain how to use the 'EnvBinder' class
Browse files Browse the repository at this point in the history
  • Loading branch information
MrDave1999 committed May 30, 2022
1 parent 3a20384 commit 1c0c314
Show file tree
Hide file tree
Showing 2 changed files with 132 additions and 0 deletions.
2 changes: 2 additions & 0 deletions docs/articles/toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
href: load_envfile_without_altering_environment.md
- name: Accessing environment variables
href: accessing_environment_variables.md
- name: Bind the model instance with the configuration keys
href: using_binder.md
- name: Required Keys
href: required_keys.md
- name: Load .env file based on environment
Expand Down
130 changes: 130 additions & 0 deletions docs/articles/using_binder.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
# Bind the model instance with the configuration keys

## Introduction

Start by creating the model that will represent the application configuration:
```cs
class AppSettings
{
[EnvKey("CONNECTION_STRING")]
public string ConnectionString { get; set; }

[EnvKey("SECRET_KEY")]
public string SecretKey { get; set; }
}
```
The `EnvKey` attribute is used in case the key names do not match the properties and this is because the key names in a .env file usually follow this convention: `KEY_NAME=VALUE` (UpperCase + SnakeCase).

In case the key names of a .env file match the properties, then it is not necessary to use the attribute (*or decorator*):
```cs
class AppSettings
{
public string ConnectionString { get; set; }
public string SecretKey { get; set; }
}
```
Then call the `Bind` method to bind the `AppSettings` class to the keys of a .env file:
```cs
new EnvLoader().Load(); // You must first load the .env file
var settings = new EnvBinder().Bind<AppSettings>();
string key1 = settings.ConnectionString;
string key2 = settings.SecretKey;
```
The `AppSettings` class must follow the following rules:
- Each property must be `public`.
- Each property must be read-write.

## Observation

If you use the `EnvBinder` class, then you no longer need to use the [EnvValidator](required_keys.md) class, and this is because the `EnvBinder.Bind` method already throws an exception in case the key is not present in the application, so it would be redundant to use both classes.

## Configuration options

### IgnoreException

It tells the `Bind` method not to throw an exception when it encounters one or more errors:
```cs
var settings = new EnvBinder()
.IgnoreException()
.Bind<AppSettings>();
```

### AllowBindNonPublicProperties

It tells the `Bind` method that it can bind non-public properties:
```cs
class AppSettings
{
public string ConnectionString { get; set; }
internal string SecretKey { get; set; }
}

var settings = new EnvBinder()
.AllowBindNonPublicProperties()
.Bind<AppSettings>();
```

## Error handling

You can handle the error through the `EnvValidationResult` class instead of throwing an exception:
```cs
new EnvLoader().Load();
var settings = new EnvBinder()
.IgnoreException() // To ignore the exception thrown by the binder.
.Bind<AppSettings>(out EnvValidationResult result);

if(result.HasError())
{
string msg = result.ErrorMessages;
System.Console.WriteLine(msg);
}
else
{
// Execute some action when there is no error.
}
```

## Injecting a Provider

The `EnvBinder` class is flexible, it adapts to any provider, so you can use it to bind the model instance to any environment variables provider (such as the current environment or a dictionary).

Example:
```cs
var envVars = new EnvLoader()
.AvoidModifyEnvironment()
.Load();

var settings = new EnvBinder(provider: envVars).Bind<AppSettings>();
```
In the above example, the `Load` method does not modify the environment, so the environment variables are obtained from a dictionary.

The `Load` method will return an instance that implements the `IEnvironmentVariablesProvider` interface and the instance is then injected into the constructor of the `EnvBinder` class. Therefore, the `Bind` method is binding the instance of the model with the keys that are in the provider (which in this case is a `dictionary<string, string>`).

## Register model as a service

If you want to use a DI Container as [Microsoft.Extensions.DependencyInjection](https://www.nuget.org/packages/Microsoft.Extensions.DependencyInjection), you must register the model as a service so that the container takes care of injecting the service when required:
```cs
// In Program.cs:
new EnvLoader().Load(); // You must first load the .env file
var settings = new EnvBinder().Bind<AppSettings>();
var services = new ServiceCollection();
services.AddSingleton<AppSettings>(settings); // Register the model as a service
```
If you are using **ASP.NET Core 3.1**, you must register the service in the `ConfigureServices` method of the `Startup` class:
```cs
public void ConfigureServices(IServiceCollection services)
{
new EnvLoader().Load(); // You must first load the .env file
var settings = new EnvBinder().Bind<AppSettings>();
services.AddSingleton<AppSettings>(settings); // Register the model as a service
}
```
In **ASP.NET Core 6**, you must register the service in `Program.cs`:
```cs
var builder = WebApplication.CreateBuilder(args);
// You must first load the .env file
new EnvLoader().Load();
var settings = new EnvBinder().Bind<AppSettings>();
// Register the model as a service
builder.Services.AddSingleton<AppSettings>(settings);
```

0 comments on commit 1c0c314

Please sign in to comment.