Exploring Enums And Ways Of Implementing In Different Layers Of Application

Introduction To Enums

Enums are user-defined data types. Inside they are integers and play a very important role in application development. They solve most of the problems and help us define the boundaries for allowed values.

Let us explore the number of ways to work with enum in C#.

Key Points

  1. Enums are part of the System namespace.
  2. They are by default non-nullable value types and behave like structs.
  3. The hierarchy is as follows, Objects → System.ValueType → System.Enum → (or enum)

Enums are of 2 types,

  1. Simple Enum Declaration
  2. Flag Enum Declaration

Simple Declaration

These are simple enum declarations, we create an enum and by default value gets assigned starting from 0 or we can explicitly assign numerical value to each enum value.

public enum SingleColor {
    RED,
    GREEN,
    BLUE
}

Flag Enums Declaration

These are much more powerful than simple Enums and support multiple values assignment. Underneath, they work based on bits value and the numeric assignment for these values should not be a simple sequence. We will see this next. To use this we need to declare a flag attribute at the top of an enum.

[Flags]
public enum Colors {
    RED = 1,
        GREEN = 2,
        BLUE = 4
}

Setting enum values

Simple Enum

Reading a simple enum is straightforward.

var selectedColor = SingleColor.BLUE;
Console.WriteLine(selectedColor); //BLUE

Flag Enum

Flag Enums contains multiple values and works on the bits data type. So, there are multiple ways to read flag Enums.

var selectedColors = Colors.BLUE | Colors.GREEN | Colors.RED;
Console.WriteLine(selectedColors); //RED, GREEN, BLUE

Extending enum properties

For extending, we can use Extension methods. Let us understand one example. We will use the extension method to check if color exists in Flag Enum.

public static bool IsSelectedColor(this Colors colors, Colors color) {
    return colors.HasFlag(color);
}
var selectedColorBG = EnumsHandler.Colors.BLUE | EnumsHandler.Colors.GREEN;
Console.WriteLine("Is Blue Selected: " + selectedColorBG.IsSelectedColor(EnumsHandler.Colors.BLUE)); //True
Console.WriteLine("Is Red Selected: " + selectedColorBG.IsSelectedColor(EnumsHandler.Colors.RED)); //False

Enums in .NET Web API

In this example, we will check how enums work in Web API requests. What happens when we don’t validate and how we can validate it.

We are going to use the Colors enum used above. We will test with Flag enum. This code will also work for simple enum except that it will return only 1 value.

The controller's code is below,

[Route("api/[controller]")]
[ApiController]
public class ValuesController: ControllerBase {
    [HttpPost]
    public IActionResult Colors(EnumRequest request) {
        return Ok(new {
            result = "Selected Color is : " + request.ColorRequest
        });
    }
}

Without Validation

Now, we will create a request model without validation.

public class EnumRequest {
    public EnumsHandler.Colors ColorRequest {
        get;
        set;
    }
}

We will send the value 100, and the output will look like below. This case will return 100 because no enum uses 100 as an assignment. In the next section, we will look for ways to avoid such invalid requests.

Exploring Enums And Ways Of Implementing In Different Layers Of Application

Next, we can send valid values i.e. 1/2/4 or their combination since it is a flag enum. In this case, I will send 6 which returns 2 colors using 2+4 logic in simple words. Let’s see what the response is.

Exploring Enums And Ways Of Implementing In Different Layers Of Application

With Validation

Validating enums is easy, we have enum data type attribute available. This will restrict the use of values depending upon enum boundaries. It will return 400 Bad Request for Invalid requests and 200 as a convention when the value is valid.

using System.ComponentModel.DataAnnotations;
public class EnumRequest {
    [EnumDataType(typeof(EnumsHandler.Colors))]
    public EnumsHandler.Colors ColorRequest {
        get;
        set;
    }
}

Now, we will try the above scenarios again,

Using 100 in request,

Exploring Enums And Ways Of Implementing In Different Layers Of Application

This time we will try using 7 as it will show all the colors, 1+2+4 adds up all the enum values and returns 7.

Exploring Enums And Ways Of Implementing In Different Layers Of Application

Nullable Enums

This is a very small topic. We can also null the enum values when our business requirement wants us to do that. This step is simple and straightforward. We will modify the above logic a little bit to replicate the null behavior.

Right now, if we send a null value it will return 400 Bad Request as Response.

Exploring Enums And Ways Of Implementing In Different Layers Of Application

Now, let us add a nullable operator in the request model. We can simply add “?” and it will work.

It is shorthand for Nullable<> operator.

[EnumDataType(typeof(EnumsHandler.Colors))]
public EnumsHandler.Colors ? ColorRequest {
    get;
    set;
}

Exploring Enums And Ways Of Implementing In Different Layers Of Application

Enum conversions in entity framework core

Enums are numbers internally. So should we explicitly convert them to string when saving them to our database? Or should we save the numbers and read them as enums from our application. This usage entirely depends on how we want to handle business use cases. There are various ways to handle this. In this example, I will show you how we can use value converters to save Enum as String in our database.

  1. We will download Microsoft.EntityFrameworkCore Nuget Package.
  2. Create a database context.
  3. And seed with data for testing with and without scenarios.

Our code looks like this right now,

public class AppContext: DbContext {
    public AppContext(DbContextOptions < AppContext > options): base(options) {}
    public class Test {
        public int Id {
            get;
            set;
        }
        public EnumsHandler.Colors SelectedColor {
            get;
            set;
        }
    }
    public DbSet < Test > Tests {
        get;
        set;
    }
    protected override void OnModelCreating(ModelBuilder modelBuilder) {
        modelBuilder.Entity < Test > ().HasData(new Test {
            Id = 1, SelectedColor = EnumsHandler.Colors.BLUE
        });
        modelBuilder.Entity < Test > ().HasData(new Test {
            Id = 2, SelectedColor = EnumsHandler.Colors.GREEN
        });
        modelBuilder.Entity < Test > ().HasData(new Test {
            Id = 3, SelectedColor = EnumsHandler.Colors.RED
        });
        modelBuilder.Entity < Test > ().HasData(new Test {
            Id = 4, SelectedColor = EnumsHandler.Colors.BLUE | EnumsHandler.Colors.GREEN
        });
        modelBuilder.Entity < Test > ().HasData(new Test {
            Id = 5, SelectedColor = EnumsHandler.Colors.GREEN | EnumsHandler.Colors.RED
        });
        modelBuilder.Entity < Test > ().HasData(new Test {
            Id = 6, SelectedColor = EnumsHandler.Colors.BLUE | EnumsHandler.Colors.GREEN | EnumsHandler.Colors.RED
        });
    }
}

This is how it is stored in our DB.

Exploring Enums And Ways Of Implementing In Different Layers Of Application

Now, we will add the converter in the OnModelCreating Method inside our DbContext implementation i.e. AppContext. Below is the code.

var colorConverter = new ValueConverter<EnumsHandler.Colors, string>(
v => v.ToString(),
v => (EnumsHandler.Colors)Enum.Parse(typeof(EnumsHandler.Colors), v));
modelBuilder.Entity<Test>()
.Property(c => c.SelectedColor)
.HasConversion(colorConverter);

Now, our output looks like below.

Exploring Enums And Ways Of Implementing In Different Layers Of Application

That’s it. Thanks for reading till the end. Let us summarize what has been covered.

Summary

  1. We took an overview of what enums are.
  2. How to extend the enums.
  3. Validating enums in Web API.
  4. Creating Nullable enums.
  5. Saving and Converting enums to and from in Database using Entity Framework Core.

Thanks for reading. Hope you found this useful.