• Stars
    star
    2,178
  • Rank 21,180 (Top 0.5 %)
  • Language
    C#
  • License
    MIT License
  • Created almost 7 years ago
  • Updated about 1 month ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A base class for quickly and easily creating strongly typed enum replacements in C#.

NuGetNuGet Last Publish Ardalis.SmartEnum to NuGet

Table Of Contents

Sub-packages

SmartEnum.AutoFixture: NuGetNuGetpublish SmartEnum.AutoFixture to nuget

SmartEnum.Dapper: NuGetNuGetpublish SmartEnum.Dapper to nuget

SmartEnum.EFCore: NuGetNuGetpublish SmartEnum.EFCore to nuget

SmartEnum.JsonNet: NuGetNuGetpublish jsonnet to nuget

SmartEnum.MessagePack: NuGetNuGetpublish SmartEnum.MessagePack to nuget

SmartEnum.ProtoBufNet: NuGetNuGetpublish SmartEnum.ProtoBufNet to nuget

SmartEnum.SystemTextJson: NuGetNuGetpublish SmartEnum.SystemTextJson to nuget

SmartEnum.Utf8Json: NuGetNuGetpublish SmartEnum.Utf8Json to nuget

Give a Star!

If you like or are using this project please give it a star. Thanks!

Smart Enum

An implementation of a type-safe object-oriented alternative to C# enum.

Contributors

Thanks to Scott Depouw, Antão Almada, and Nagasudhir Pulla for help with this project!

Install

The framework is provided as a set of NuGet packages. In many cases you'll only need the base package, but if you need serialization and/or ORM support there are many implementation-specific packages available to assist.

To install the minimum requirements:

Install-Package Ardalis.SmartEnum

To install support for serialization, AutoFixture, EF Core, Model Binding, or Dapper select the lines that apply:

Install-Package Ardalis.SmartEnum.AutoFixture
Install-Package Ardalis.SmartEnum.JsonNet
Install-Package Ardalis.SmartEnum.Utf8Json
Install-Package Ardalis.SmartEnum.MessagePack
Install-Package Ardalis.SmartEnum.ProtoBufNet
Install-Package Ardalis.SmartEnum.EFCore
Install-Package Ardalis.SmartEnum.ModelBinding
Install-Package Ardalis.SmartEnum.Dapper

Version

The latest version of the package supports .NET 7. If you don't need or aren't yet ready to move to .NET 7 or later, you should install the previous stable version, Ardalis.SmartEnum 2.1.

Example package manager command:

Install-Package Ardalis.SmartEnum -Version 2.1.0

Usage

Define your smart enum by inheriting from SmartEnum<TEnum> where TEnum is the type you're declaring. For example:

using Ardalis.SmartEnum;

public sealed class TestEnum : SmartEnum<TestEnum>
{
    public static readonly TestEnum One = new TestEnum(nameof(One), 1);
    public static readonly TestEnum Two = new TestEnum(nameof(Two), 2);
    public static readonly TestEnum Three = new TestEnum(nameof(Three), 3);

    private TestEnum(string name, int value) : base(name, value)
    {
    }
}

The default value type is int but it can be set using the second generic argument TValue. The string alias can also be set explicitly, where spaces are allowed.

using Ardalis.SmartEnum;

public sealed class TestEnum : SmartEnum<TestEnum, ushort>
{
    public static readonly TestEnum One = new TestEnum("A string!", 1);
    public static readonly TestEnum Two = new TestEnum("Another string!", 2);
    public static readonly TestEnum Three = new TestEnum("Yet another string!", 3);

    private TestEnum(string name, ushort value) : base(name, value)
    {
    }
}

Just like regular enum, more than one string can be assigned to the same value but only one value can be assigned to a string:

using Ardalis.SmartEnum;

public sealed class TestEnum : SmartEnum<TestEnum>
{
    public static readonly TestEnum One = new TestEnum(nameof(One), 1);
    public static readonly TestEnum Two = new TestEnum(nameof(Two), 2);
    public static readonly TestEnum Three = new TestEnum(nameof(Three), 3);
    public static readonly TestEnum AnotherThree = new TestEnum(nameof(AnotherThree), 3);
    // public static TestEnum Three = new TestEnum(nameof(Three), 4); -> throws exception

    private TestEnum(string name, int value) : base(name, value)
    {
    }
}

In this case, TestEnum.FromValue(3) will return the first instance found, either TestEnum.Three or TestEnum.AnotherThree. No order should be assumed.

The Value content is used when comparing two smart enums, while Name is ignored:

TestEnum.One.Equals(TestEnum.One); // returns true
TestEnum.One.Equals(TestEnum.Three); // returns false
TestEnum.Three.Equals(TestEnum.AnotherThree); // returns true

Inheritance can be used to add "behavior" to a smart enum.

This example adds a BonusSize property, avoiding the use of the switch typically used with regular enums:

using Ardalis.SmartEnum;

public abstract class EmployeeType : SmartEnum<EmployeeType>
{
    public static readonly EmployeeType Manager = new ManagerType();
    public static readonly EmployeeType Assistant = new AssistantType();

    private EmployeeType(string name, int value) : base(name, value)
    {
    }

    public abstract decimal BonusSize { get; }

    private sealed class ManagerType : EmployeeType
    {
        public ManagerType() : base("Manager", 1) {}

        public override decimal BonusSize => 10_000m;
    }

    private sealed class AssistantType : EmployeeType
    {
        public AssistantType() : base("Assistant", 2) {}

        public override decimal BonusSize => 1_000m;
    }
}

You can take this a step further and use the ManagerType and associated BonusSize property in a parent class like so:

public class Manager
{
    private ManagerType _managerType { get; set; }
    public string Type
    {
        get => _managerType.Name;
        set
        {
            if (!ManagerType.TryFromName(value, true, out var parsed))
            {
                throw new Exception($"Invalid manage type of '{value}'");
            }
            _managerType = parsed;
        }
    }

    public string BonusSize
    {
        get => _managerType.BonusSize();
        set => _bonusSize_ = value;
    }
}

This other example implements a state machine. The method CanTransitionTo() returns true if it's allowed to transition from current state to next; otherwise returns false.

using Ardalis.SmartEnum;

public abstract class ReservationStatus : SmartEnum<ReservationStatus>
{
    public static readonly ReservationStatus New = new NewStatus();
    public static readonly ReservationStatus Accepted = new AcceptedStatus();
    public static readonly ReservationStatus Paid = new PaidStatus();
    public static readonly ReservationStatus Cancelled = new CancelledStatus();

    private ReservationStatus(string name, int value) : base(name, value)
    {
    }

    public abstract bool CanTransitionTo(ReservationStatus next);

    private sealed class NewStatus: ReservationStatus
    {
        public NewStatus() : base("New", 0)
        {
        }

        public override bool CanTransitionTo(ReservationStatus next) =>
            next == ReservationStatus.Accepted || next == ReservationStatus.Cancelled;
    }

    private sealed class AcceptedStatus: ReservationStatus
    {
        public AcceptedStatus() : base("Accepted", 1)
        {
        }

        public override bool CanTransitionTo(ReservationStatus next) =>
            next == ReservationStatus.Paid || next == ReservationStatus.Cancelled;
    }

    private sealed class PaidStatus: ReservationStatus
    {
        public PaidStatus() : base("Paid", 2)
        {
        }

        public override bool CanTransitionTo(ReservationStatus next) =>
            next == ReservationStatus.Cancelled;
    }

    private sealed class CancelledStatus: ReservationStatus
    {
        public CancelledStatus() : base("Cancelled", 3)
        {
        }

        public override bool CanTransitionTo(ReservationStatus next) =>
            false;
    }
}

List

You can list all of the available options using the enum's static List property:

foreach (var option in TestEnum.List)
    Console.WriteLine(option.Name);

List returns an IReadOnlyCollection so you can use the Count property to efficiently get the number of available options.

var count = TestEnum.List.Count;

FromName()

Access an instance of an enum by matching a string to its Name property:

var myEnum = TestEnum.FromName("One");

Exception SmartEnumNotFoundException is thrown when name is not found. Alternatively, you can use TryFromName that returns false when name is not found:

if (TestEnum.TryFromName("One", out var myEnum))
{
    // use myEnum here
}

Both methods have a ignoreCase parameter (the default is case sensitive).

FromValue()

Access an instance of an enum by matching its value:

var myEnum = TestEnum.FromValue(1);

Exception SmartEnumNotFoundException is thrown when value is not found. Alternatively, you can use TryFromValue that returns false when value is not found:

if (TestEnum.TryFromValue(1, out var myEnum))
{
    // use myEnum here
}

ToString()

Display an enum using the ToString() override:

Console.WriteLine(TestEnum.One); // One

Switch

Given an instance of a TestEnum, switch depending on value:

switch(testEnumVar.Name)
{
    case nameof(TestEnum.One):
        ...
        break;
    case nameof(TestEnum.Two):
        ...
        break;
    case nameof(TestEnum.Three):
        ...
        break;
    default:
        ...
        break;
}

Using pattern matching:

switch(testEnumVar)
{
    case null:
        ...
        break;
    case var e when e.Equals(TestEnum.One):
        ...
        break;
    case var e when e.Equals(TestEnum.Two):
        ...
        break;
    case var e when e.Equals(TestEnum.Three):
        ...
        break;
    default:
        ...
        break;
}

Because of the limitations of pattern matching SmartEnum also provides a fluent interface to help create clean code:

testEnumVar
    .When(TestEnum.One).Then(() => ... )
    .When(TestEnum.Two).Then(() => ... )
    .When(TestEnum.Three).Then(() => ... )
    .Default( ... );

N.B. For performance critical code the fluent interface carries some overhead that you may wish to avoid. See the available benchmarks code for your use case.

SmartFlagEnum

Support has been added for a Flag functionality. This feature is similar to the behaviour seen when applying the [Flag] attribute to Enums in the .NET Framework All methods available on the SmartFlagEnum class return an IEnumerable<SmartFlagEnum> with one or more values depending on the value provided/method called. Some Functionality is shared with the original SmartEnum class, listed below are the variations.

Setting SmartFlagEnum Values

When setting the values for a SmartFlagEnum It is imperative to provide values as powers of two. If at least one value is not set as power of two or two or more power of two values are provided inconsecutively (eg: 1, 2, no four!, 8) a SmartFlagEnumDoesNotContainPowerOfTwoValuesException will be thrown.

public class SmartFlagTestEnum : SmartFlagEnum<SmartFlagTestEnum>
    {
        public static readonly SmartFlagTestEnum None = new SmartFlagTestEnum(nameof(None), 0);
        public static readonly SmartFlagTestEnum Card = new SmartFlagTestEnum(nameof(Card), 1);
        public static readonly SmartFlagTestEnum Cash = new SmartFlagTestEnum(nameof(Cash), 2);
        public static readonly SmartFlagTestEnum Bpay = new SmartFlagTestEnum(nameof(Bpay), 4);
        public static readonly SmartFlagTestEnum Paypal = new SmartFlagTestEnum(nameof(Paypal), 8);
        public static readonly SmartFlagTestEnum BankTransfer = new SmartFlagTestEnum(nameof(BankTransfer), 16);

        public SmartFlagTestEnum(string name, int value) : base(name, value)
        {
        }
    }

This behaviour can be disabled by applying the AllowUnsafeFlagEnumValuesAttribute to the smart enum class. Note: If power of two values are not provided the SmarFlagEnum will not behave as expected!

[AllowUnsafeFlagEnumValues]
public class SmartFlagTestEnum : SmartFlagEnum<SmartFlagTestEnum>
    {
        public static readonly SmartFlagTestEnum None = new SmartFlagTestEnum(nameof(None), 0);
        public static readonly SmartFlagTestEnum Card = new SmartFlagTestEnum(nameof(Card), 1);
        public static readonly SmartFlagTestEnum Cash = new SmartFlagTestEnum(nameof(Cash), 2);
        public static readonly SmartFlagTestEnum Bpay = new SmartFlagTestEnum(nameof(Bpay), 4);
        public static readonly SmartFlagTestEnum Paypal = new SmartFlagTestEnum(nameof(Paypal), 8);
        public static readonly SmartFlagTestEnum BankTransfer = new SmartFlagTestEnum(nameof(BankTransfer), 16);

        public SmartFlagTestEnum(string name, int value) : base(name, value)
        {
        }
    }

Combination values can be provided explicitly and will be returned in place of the multiple flag values that would have been returned from the FromValue() method.

public class SmartFlagTestEnum : SmartFlagEnum<SmartFlagTestEnum>
    {
        public static readonly SmartFlagTestEnum None = new SmartFlagTestEnum(nameof(None), 0);
        public static readonly SmartFlagTestEnum Card = new SmartFlagTestEnum(nameof(Card), 1);
        public static readonly SmartFlagTestEnum Cash = new SmartFlagTestEnum(nameof(Cash), 2);
        public static readonly SmartFlagTestEnum CardAndCash = new SmartFlagTestEnum(nameof(CardAndCash), 3); -- Explicit `Combination` value
        public static readonly SmartFlagTestEnum Bpay = new SmartFlagTestEnum(nameof(Bpay), 4);
        public static readonly SmartFlagTestEnum Paypal = new SmartFlagTestEnum(nameof(Paypal), 8);
        public static readonly SmartFlagTestEnum BankTransfer = new SmartFlagTestEnum(nameof(BankTransfer), 16);

        public SmartFlagTestEnum(string name, int value) : base(name, value)
        {
        }
    }

These explicit values can be provided above the highest allowable flag value without consequence, however attempting to access a value that is higher than the maximum flag value that has not explicitly been provided (for example 4) will cause a SmartEnumNotFoundException to be thrown.

public class SmartFlagTestEnum : SmartFlagEnum<SmartFlagTestEnum>
    {
        public static readonly SmartFlagTestEnum None = new SmartFlagTestEnum(nameof(None), 0);
        public static readonly SmartFlagTestEnum Card = new SmartFlagTestEnum(nameof(Card), 1);
        public static readonly SmartFlagTestEnum Cash = new SmartFlagTestEnum(nameof(Cash), 2);
        public static readonly SmartFlagTestEnum AfterPay = new SmartFlagTestEnum(nameof(AfterPay), 5);

        public SmartFlagTestEnum(string name, int value) : base(name, value)
        {
        }
    }

    var myFlagEnums = FromValue(3) -- Works!
    -and-
    var myFlagEnums = FromValue(5) -- Works!
    -but-
    Var myFlagEnums = FromValue(4) -- will throw an exception :(

A Negative One (-1) value may be provided as an All value. When a value of -1 is passed into any of the FromValue() methods an IEnumerable containing all values (excluding 0) will be returned. If an explicit Combination value exists with a value of -1 this will be returned instead.

public class SmartFlagTestEnum : SmartFlagEnum<SmartFlagTestEnum>
    {
        public static readonly SmartFlagTestEnum All = new SmartFlagTestEnum(nameof(All), -1);
        public static readonly SmartFlagTestEnum None = new SmartFlagTestEnum(nameof(None), 0);
        public static readonly SmartFlagTestEnum Card = new SmartFlagTestEnum(nameof(Card), 1);
        public static readonly SmartFlagTestEnum Cash = new SmartFlagTestEnum(nameof(Cash), 2);
        public static readonly SmartFlagTestEnum Bpay = new SmartFlagTestEnum(nameof(Bpay), 4);
        public static readonly SmartFlagTestEnum Paypal = new SmartFlagTestEnum(nameof(Paypal), 8);
        public static readonly SmartFlagTestEnum BankTransfer = new SmartFlagTestEnum(nameof(BankTransfer), 16);

        public SmartFlagTestEnum(string name, int value) : base(name, value)
        {
        }
    }

Usage - (SmartFlagEnum)

public abstract class EmployeeType : SmartFlagEnum<EmployeeType>
    {
        public static readonly EmployeeType Director = new DirectorType();
        public static readonly EmployeeType Manager = new ManagerType();
        public static readonly EmployeeType Assistant = new AssistantType();

        private EmployeeType(string name, int value) : base(name, value)
        {
        }

        public abstract decimal BonusSize { get; }

        private sealed class DirectorType : EmployeeType
        {
            public DirectorType() : base("Director", 1) { }

            public override decimal BonusSize => 100_000m;
        }

        private sealed class ManagerType : EmployeeType
        {
            public ManagerType() : base("Manager", 2) { }

            public override decimal BonusSize => 10_000m;
        }

        private sealed class AssistantType : EmployeeType
        {
            public AssistantType() : base("Assistant", 4) { }

            public override decimal BonusSize => 1_000m;
        }
    }

    public class SmartFlagEnumUsageExample
    {
        public void UseSmartFlagEnumOne()
        {
            var result = EmployeeType.FromValue(3).ToList();

            var outputString = "";
            foreach (var employeeType in result)
            {
                outputString += $"{employeeType.Name} earns ${employeeType.BonusSize} bonus this year.\n";
            }

                => "Director earns $100000 bonus this year.\n"
                   "Manager earns $10000 bonus this year.\n"
        }

        public void UseSmartFlagEnumTwo()
        {
            EmployeeType.FromValueToString(-1)
                => "Director, Manager, Assistant"
        }

        public void UseSmartFlagEnumTwo()
        {
            EmployeeType.FromValueToString(EmployeeType.Assistant | EmployeeType.Director)
                => "Director, Assistant"
        }
    }

FromName()

Access an IEnumerable of enum instances by matching a string containing one or more enum names seperated by commas to its Names property:

var myFlagEnums = TestFlagEnum.FromName("One, Two");

Exception SmartEnumNotFoundException is thrown when no names are found. Alternatively, you can use TryFromName that returns false when no names are found:

if (TestFlagEnum.TryFromName("One, Two", out var myFlagEnums))
{
    // use myFlagEnums here
}

Both methods have a ignoreCase parameter (the default is case sensitive).

FromValue()

Access an IEnumerable of enum instances by matching a value:

var myFlagEnums = TestFlagEnum.FromValue(3);

Exception SmartEnumNotFoundException is thrown when no values are found. Alternatively, you can use TryFromValue that returns false when values are not found:

if (TestFlagEnum.TryFromValue(3, out var myFlagEnums))
{
    // use myFlagEnums here
}

Note: Negative values other than (-1) passed into this method will cause a NegativeValueArgumentException to be thrown, this behaviour can be disabled by applying the AllowNegativeInput attribute to the desired SmartFlagEnum class.

[AllowNegativeInput]
public class SmartFlagTestEnum : SmartFlagEnum<SmartFlagTestEnum>
    {
        public static readonly SmartFlagTestEnum None = new SmartFlagTestEnum(nameof(None), 0);
        public static readonly SmartFlagTestEnum Card = new SmartFlagTestEnum(nameof(Card), 1);

        public SmartFlagTestEnum(string name, int value) : base(name, value)
        {
        }
    }

Note: FromValue() will accept any input that can be succesfully parsed as an integer. If an invalid value is supplied it will throw an InvalidFlagEnumValueParseException.

FromValueToString()

Return a string representation of a series of enum instances name's:

var myFlagEnumString = TestFlagEnum.FromValueToString(3);

Exception SmartEnumNotFoundException is thrown when no values are found. Alternatively, you can use TryFromValueToString that returns false when values are not found:

if (TestFlagEnum.TryFromValueToString(3, out var myFlagEnumsAsString))
{
    // use myFlagEnumsAsString here
}

Note: Negative values other than (-1) passed into this method will cause a NegativeValueArgumentException to be thrown, this behaviour can be disabled by applying the AllowNegativeInput attribute to the desired SmartFlagEnum class.

BitWiseOrOperator

The FromValue() methods allow the Or ( | ) operator to be used to add enum values together and provide multiple values at once.

var myFlagEnums = TestFlagEnum.FromValue(TestFlagEnum.One | TestFlagEnum.Two);

This will only work where the type of the SmartFlagEnum has been specified as Int32 or else can be explicitly cast as an Int32.

var myFlagEnums = TestFlagEnumDecimal.FromValue((int)TestFlagEnum.One | (int)TestFlagEnum.Two);

Persisting with EF Core 2.1 or higher

EF Core 2.1 introduced value conversions which can be used to map SmartEnum types to simple database types. For example, given an entity named Policy with a property PolicyStatus that is a SmartEnum, you could use the following code to persist just the value to the database:

protected override void OnModelCreating(ModelBuilder builder)
{
    base.OnModelCreating(builder);

    builder.Entity<Policy>()
        .Property(p => p.PolicyStatus)
        .HasConversion(
            p => p.Value,
            p => PolicyStatus.FromValue(p));
}

Remember, you need to implement your own parameterless constructor to make it works with db context. See #103 issue.

Using SmartEnum.EFCore

EF Core 6 introduced pre-convention model configuration which allows value conversions to be configured for specific types within a model. If you have installed Ardalis.SmartEnum.EFCore it is sufficient to add the following line at the beginning of the ConfigureConventions method:

protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
{
    configurationBuilder.ConfigureSmartEnum();

    ...
}

For previous versions of EF Core, the following line can be added at the end of the OnModelCreating method:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    ...

    modelBuilder.ConfigureSmartEnum();
}

AutoFixture support

New instance of a SmartEnum should not be created. Instead, references to the existing ones should always be used. AutoFixture by default doesn't know how to do this. The Ardalis.SmartEnum.AutoFixture package includes a specimen builder for SmartEnum. Simply add the customization to the IFixture builder:

var fixture = new Fixture()
    .Customize(new SmartEnumCustomization());

var smartEnum = fixture.Create<TestEnum>();

Json.NET support

When serializing a SmartEnum to JSON, only one of the properties (Value or Name) should be used. Json.NET by default doesn't know how to do this. The Ardalis.SmartEnum.JsonNet package includes a couple of converters to achieve this. Simply use the attribute JsonConverterAttribute to assign one of the converters to the SmartEnum to be de/serialized:

public class TestClass
{
    [JsonConverter(typeof(SmartEnumNameConverter<TestEnum,int>))]
    public TestEnum Property { get; set; }
}

uses the Name:

{
  "Property": "One"
}

While this:

public class TestClass
{
    [JsonConverter(typeof(SmartEnumValueConverter<TestEnum,int>))]
    public TestEnum Property { get; set; }
}

uses the Value:

{
  "Property": 1
}

Note: The SmartFlagEnum works identically to the SmartEnum when being Serialized and Deserialized.

Dapper support

To enable Dapper support for SmartEnum values, add a SmartEnumTypeHandler to SqlMapper for the given SmartEnum type. There are two inheritors of SmartEnumTypeHandler: SmartEnumByNameTypeHandler, which maps the Name of a SmartEnum to a database column, and SmartEnumByValueTypeHandler, which maps the Value of a SmartEnum to a database column.

// Maps the name of TestEnum objects (e.g. "One", "Two", or "Three") to a database column.
SqlMapper.AddTypeHandler(typeof(TestEnum), new SmartEnumByNameTypeHandler<TestEnum>());
// Maps the value of TestEnum objects (e.g. 1, 2, or 3) to a database column.
SqlMapper.AddTypeHandler(typeof(TestEnum), new SmartEnumByValueTypeHandler<TestEnum>());

DapperSmartEnum

To avoid needing to explicitly register a SmartEnum type with Dapper, it can be done automatically by inheriting from DapperSmartEnumByName or DapperSmartEnumByValue instead of from SmartEnum.

public class TestEnumByName : DapperSmartEnumByName<TestEnumByName>
{
    public static readonly TestEnumByName One = new TestEnumByName(1);
    public static readonly TestEnumByName Two = new TestEnumByName(2);
    public static readonly TestEnumByName Three = new TestEnumByName(3);

    protected TestEnumByName(int value, [CallerMemberName] string name = null) : base(name, value)
    {
    }
}
public class TestEnumByValue : DapperSmartEnumByValue<TestEnumByValue>
{
    public static readonly TestEnumByValue One = new TestEnumByValue(1);
    public static readonly TestEnumByValue Two = new TestEnumByValue(2);
    public static readonly TestEnumByValue Three = new TestEnumByValue(3);

    protected TestEnumByValue(int value, [CallerMemberName] string name = null) : base(name, value)
    {
    }
}

Inheritors of DapperSmartEnum can be decorated with custom attributes in order to configure its type handler. Use DbTypeAttribute (e.g. [DbType(DbType.String)]) to specify that parameters should have their DbType property set to the specified value. Use DoNotSetDbTypeAttribute (e.g. [DoNotSetDbType]) to specify that parameters should not have their DbType property set. Use IgnoreCaseAttribute (e.g. [IgnoreCase]) when inheriting from DapperSmartEnumByName to specify that database values do not need to match the case of a SmartEnum Name.

Examples in the Real World

Search for more

References

More Repositories

1

CleanArchitecture

Clean Architecture Solution Template: A starting point for Clean Architecture with ASP.NET Core
C#
16,284
star
2

GuardClauses

A simple package with guard clause extensions.
C#
3,063
star
3

ApiEndpoints

A project for supporting API Endpoints in ASP.NET Core web applications.
C#
2,934
star
4

Specification

Base class with tests for adding specifications to a DDD model
C#
1,922
star
5

pluralsight-ddd-fundamentals

Sample code for the Pluralsight DDD Fundamentals course by Julie Lerman and Steve "ardalis" Smith
CSS
841
star
6

Result

A result abstraction that can be mapped to HTTP response codes if needed.
C#
819
star
7

CleanArchitecture.WorkerService

A solution template using Clean Architecture for building a .NET Core Worker Service.
C#
720
star
8

ddd-guestbook

A DDD guestbook example written for ASP.NET Core
C#
691
star
9

kata-catalog

My list of code katas
C#
670
star
10

DesignPatternsInCSharp

Samples associated with Pluralsight design patterns in c# courses.
C#
518
star
11

DDD-NoDuplicates

Some design approaches to enforcing a business rule requiring no duplicates. Domain driven design.
C#
512
star
12

SolidSample

C#
474
star
13

new-software-project-checklist

The ultimate new software project decision/question checklist
443
star
14

ddd-vet-sample

A sample meant to demonstrate domain driven design using a veterinary hospital management system.
C#
305
star
15

OrganizingAspNetCore

Offers several different ways to organize content in ASP.NET Core MVC and Razor Pages projects.
C#
207
star
16

Ardalis.Extensions

Some random C# extension methods I've found useful. Published as Ardalis.Extensions on Nuget.
C#
147
star
17

WebApiBestPractices

Resources related to my Pluralsight course on this topic.
C#
144
star
18

CachedRepository

A sample demonstrating the CachedRepository pattern
C#
104
star
19

HttpClientTestExtensions

Extensions for testing HTTP endpoints and deserializing the results. Currently works with XUnit.
C#
92
star
20

CertExpirationCheck

A simple xUnit C# test showing how to verify a certificate for a domain has at least 30 days before it expires.
C#
79
star
21

DotNetDataAccessTour

A tour of different data access approaches in .NET 8+.
C#
73
star
22

AspNetCoreStartupServices

A simple demo listing all services available to an app at startup
C#
69
star
23

GettingStartedWithFilters

Filters samples associated with MSDN article
C#
67
star
24

AspNetCoreRouteDebugger

An ASP.NET Core Route Debugger implemented as a Razor Page
C#
67
star
25

Ardalis.SharedKernel

Some useful base classes, mainly used with the CleanArchitecture template. Also, a template to make your own SharedKernel nuget package.
C#
56
star
26

MediatRAspNetCore

Sample showing MediatR with ASP.NET Core
C#
50
star
27

DevIQ-gatsby

JavaScript
48
star
28

DomainEventsConsole

A console app showing domain events in action using .NET 5
C#
41
star
29

BuilderTestSample

Show how to use a builder with unit tests.
C#
40
star
30

EFCore.Extensions

Extension methods to make working with EF Core easier.
C#
38
star
31

CSharpGenerics

Some samples using C# generics for a Pluralsight course.
C#
38
star
32

Ardalis.ApiClient

Some classes to make working with APIs easier.
C#
33
star
33

TestPatterns

Examples of approaches to unit testing different kinds of code in C#.
C#
33
star
34

StatePattern

An example of the State design pattern in C#
C#
30
star
35

MinimalWebApi

A minimal Web API for ASP.NET Core
C#
29
star
36

BlazorAuth

A sample showing how to add ASP.NET Core Identity auth options to the basic Blazor app.
C#
27
star
37

EditorConfig

A sample editorconfig file for use with .NET / C# applications
27
star
38

DevResources

A list of links to resources.
26
star
39

NotFoundMiddlewareSample

Middleware for detecting and correcting website 404 errors.
C#
25
star
40

DomainModeling

Some examples showing domain modeling tips and traps
C#
21
star
41

AggregateEvents

A sample showing how to use domain events within aggregates
C#
19
star
42

Specification.EFCore

Some utilities for EF Core to use Specifications
C#
16
star
43

LazyLoading

C#
16
star
44

TestSecureApiSample

A sample showing how to test a secure API endpoint using xunit, identityserver4, and environment variables
JavaScript
15
star
45

EulerCSharpStarter

A starting point for solving Project Euler problems using C#.
C#
14
star
46

EnumAlternative

A sample demonstrating strongly typed C# alternatives to enums.
C#
13
star
47

RouteAndBodyModelBinding

A model binder for ASP.NET Core that supports pulling in values from the route and body of a request.
C#
13
star
48

DoubleDispatchSamples

Some examples of double dispatch in C# and how to use in domain models.
C#
13
star
49

ardalis-com-gatsby

Back end content for ardalis.com running with Netlify and Gatsby.
JavaScript
12
star
50

GildedRoseStarter

A starting point for the Gilded Rose kata using dotnet core, C#, and xunit.
C#
11
star
51

ValueObjectsDemo

C#
10
star
52

MongoDbDotNetHelloWorld

Demonstrating how to get started with MongoDB as quickly as possible in dotnet
C#
10
star
53

TestingLogging

A sample showing how to test logging is working as expected in ASP.NET Core apps.
C#
10
star
54

GuardClauses.Analyzers

A project for holding Roslyn analyzers that leverage Ardalis.GuardClauses
C#
10
star
55

ValidateModel

A very small library/package that includes a model validation attribute for ASP.NET Core projects.
C#
9
star
56

RegExLib.com

Source code for the regexlib.com regular expression library site.
C#
9
star
57

SoftwareQualityWorkshop2020

Public resources supporting private software quality workshops I'm delivering in 2020.
C#
9
star
58

RepoMultiImplementation

C#
8
star
59

MediatREndpointsSample

A sample using MediatR to map endpoints using minimal apis
C#
8
star
60

DomainEventsDemo

A sample project showing how to wire up Domain Events
C#
8
star
61

MessagingDemo

C#
8
star
62

RefactoringKataAttempts2024

C#
8
star
63

AspNetCoreNewIn21

Samples showing what's new in ASP.NET Core 2.1
JavaScript
7
star
64

CSharpPropertiesExamples

Some examples of when and how C# properties work in different application scenarios.
C#
6
star
65

EulerNodeStarter

A starting point for solving Project Euler problems using node.js
JavaScript
6
star
66

RefactoringSamples

C#
6
star
67

UnitTestPerf

Some projects used to demonstrate the performance of different unit testing frameworks for .NET Core
C#
6
star
68

AccessTokenSample

A small sample showing how to create, manage, use access tokens.
C#
6
star
69

IntegrationEventSample

Sample showing Domain Events and Integration Events with Web API 2
C#
6
star
70

azure-cloud-native-book

5
star
71

ExtensionMethodSample

Some simple extension method samples
C#
5
star
72

Cachify

A .NET library to optimize data and reflection-based operations using caching.
PowerShell
5
star
73

Refactoring-To-SOLID-Pluralsight

Resources for my Pluralsight course on Refactoring to SOLID C# Code
C#
5
star
74

CodinGameFall2022

C#
5
star
75

EFCoreOwnedEntityTests

A unit test project that tests owned entities in EF Core
C#
5
star
76

EFCoreStringInterpolationDemo

Showing new EF Core 2.0 feature for raw SQL queries
C#
5
star
77

Diagrams

Text and images from UML and similar diagrams
5
star
78

RedisDotNetHelloWorld

Getting started with Redis in dotnet
C#
5
star
79

WhenAllTest

A simple app showing perf gains of using WhenAll for parallel task execution.
C#
5
star
80

AdventOfCode2022

Working on this: https://adventofcode.com for 2022
C#
4
star
81

ardalis

4
star
82

StructureMapLoggingSample

C#
4
star
83

ConsoleLoggingSample

A sample using NLog to create custom loggers that include app-specific data in the output.
C#
4
star
84

ValidationRules

A collection of validation rules for VS Web Tests
C#
3
star
85

CraftsmanshipCalendarIdeas

Ideas for next year's software craftsmanship calendar
3
star
86

CodinGameSpring2021

C#
3
star
87

Logging

Some logging utilities for .NET Core
C#
3
star
88

MigrateDotNetWithIIS

JavaScript
3
star
89

CastleWindsorSample

A console app showing the basic setup of Castle Windsor for IOC
C#
3
star
90

GeekDinnerSample

An incomplete sample showing clean code and DI in ASP.NET Core
C#
3
star
91

RegExLib

Regexlib.com source
C#
3
star
92

MontyHallMvc

An ASP.NET MVC application that lets users try out the Monty Hall problem and shows their stats.
C#
3
star
93

yarp-passthrough

The simplest YARP ASP.NET Core app that just passes everything through to another domain.
C#
3
star
94

AggregatePatterns

C#
2
star
95

EulerNode

A node.js implementation of Project Euler problems.
JavaScript
2
star
96

TennisGameKatas

C#
2
star
97

AspNetCoreLabs

2
star
98

EFCoreFeatureTests

Tests demonstrating EF Core features across versions.
C#
2
star
99

TestRepo

Just a repo for testing some things
2
star
100

FizzBuzzVS2015

A sample FizzBuzz kata implementation using VS2015
Smalltalk
2
star