Skip to content

MarkDerman/OrdinaryInfrastructure

Repository files navigation

Odin logo

OrDinary INfrastructure

License: MIT

The Odin components

... are a collection born after years of building many line-of-business applications on .NET...
The result of componentising various recurring ordinary use-cases that we kept repeating in client systems at Soulv Software.

As at Dec 2025, the library is a hodge-podge of miscellaneous bits and bobs.

With .Net Core almost 10 years old now, I have never stopped missing using invariants on my domain entities with the old Code Contracts from .NET Framework days, so I am now putting my attention to creating some form of runtime support for preconditions, postconditions and class invariants for .NET 8 and up.



Design Contracts ✏️

Coming soon... 🚧

 

Result Pattern: Result and ResultValue

NuGet Nuget

Odin.System.Result, provides several 'Result' classes, which all encapsulate the success of an operation, together with a list of messages.

Result is the simplest concept.

ResultValue adds a generic Value property.

Result and ResultValue<TValue, TMessage> add support for the Messages list to be of any type.

ResultEx and ResultValueEx come with a TMessage type that is aligned with logging failure issues.

Getting starting with Result, ResultValue, and more...

1 - Success() and Failure()

    public class HeartOfGoldService
    {
        public Result WarpSpeedToMilliways()
        {
            if (_eddie.IsOK()) return Result.Success();
            return Result.Failure(["Zaphod, that is not possible...", "Error 42"])
        }
    }

Result documentation...

Email Sending 📧

Odin.Email provides an IEmailSender with email sending support currently for Mailgun and Office365.

1 - Add configuration

{
  "EmailSending": {
    "Provider": "Mailgun",
    "DefaultFromAddress": "team@domain.com",
    "DefaultFromName": "MyTeam",
    "DefaultTags": [ "QA", "MyApp" ],
    "SubjectPrefix": "QA: ",
    "Mailgun": {
      "ApiKey": "XXX",
      "Domain": "mailgun.domain.com",
      "Region": "EU"
    }
  }
}

2 - Add package references to Odin.Email, and in this case Odin.Email.Mailgun

3 - Add IEmailSender to DI in your startup code...

    builder.Services.AddOdinEmailSending();

4 - Use IEmailSender from DI

    MyService(IEmailSender emailSender)
    {
        _emailSender = emailSender;
    }

5 - Send email

    IEmailMessage email = new EmailMessage(to, from, subject, htmlBody);
    ResultValue<string?> sendResult = await _emailSender.SendEmail(email);
Package Description Latest Version
Odin.Email IEmailSender and IEmailMessage concepts NuGet Nuget
Odin.Email.Mailgun Mailgun V3 API support NuGet Nuget
Odin.Email.Office365 Microsoft Office365 support (via MS Graph) NuGet Nuget

 

Odin.Logging 📋

NuGet Nuget

Provides an ILoggerWrapper of T that extends .NET's ILogger of T with all the LogXXX(...) calls as provided by the .NET LoggerExtensions extension methods (and a few more), for simpler logging assertion verifications.

Read more...

    // Log as you always do in your app...
   _logger.LogWarning("Ford Prefect is missing!");

    // Assert logging calls more simply in your tests...    
    _loggerWrapperMock.Verify(x => x.LogWarning(It.Is<string>(c => 
        c.Contains("Ford Prefect"))), Times.Once);
    
    // as opposed to this with ILogger
    _iLoggerMock.Verify(
        x => x.Log(
            LogLevel.Warning,
            It.IsAny<EventId>(),
            It.Is<It.IsAnyType>((state, _) =>
                state.ToString() == "Ford Prefect is missing!"),
            It.IsAny<Exception?>(),
            It.IsAny<Func<It.IsAnyType, Exception?, string>>()),
        Times.Once);

 

Razor Templating

Provides an IRazorTemplateRenderer for rendering .cshtml Razor files outside of the context of ASP.Net.

    // 1 - Add to DI in startup... 
    services.AddOdinRazorTemplating(typeof(AppBuilder).Assembly, "App.EmailViews.");
    
    // 2 - Render cshtml views by passing in a model
    ResultValue<string> result = await _razorTemplateRenderer
          .RenderAsync("AlertsEmail", alertingEmailModel);
    myEmail.Body = result.Value;
Package Latest Version
Odin.Templating.Razor.Abstractions NuGet Nuget
Odin.Templating.Razor NuGet Nuget

 

StringEnum

NuGet Nuget

Odin.System.StringEnum provides enum-like behaviour for a set of string values via StringEnum, as well as a useful StringEnumMemberAttribute. Read more...

1 - Define your string 'enum' with public string constants

    public class LoaderTypes : StringEnum<LoaderTypes>
    {
        public const string File = "FILE";
        public const string DynamicSql = "DYNAMIC-SQL";
    }

2 - Use like an enum

    if (loaderOptions.LoaderType == LoaderTypes.DynamicSql)

3 - HasValue

    bool memberExists = LoaderTypes.HasValue("CUSTOM"); // returns false

4 - Values property

    string message = $"Valid members are: {string.Join(" | ", LoaderTypes.Values)}"

5 - Validation attribute

    public record LoaderEditModel : IValidatableObject
    {
        [Required(AllowEmptyStrings = false)]
        [StringEnumMember<LoaderTypes>]
        public required string Loader { get; set; }
        ...
    }

Other Libraries

In various states of incubation, deprecation or neglect...

Area Description Status Version
Remote files \ SFTP \ FTPS An abstraction of SFTP and FTPS file operations. Needs attention NuGet
Configuration - AzureBlobJson Support for json configuration source in Azure Blob Storage NuGet
SQL scripts runner Useful for running database migration scripts at application deployment time. NuGet
Utility - Tax Simple support for storing tax rate changes over time in application configuration, and then getting tax rates as at any date. No docs NuGet
BackgroundProcessing Wrapper around Hangfire Deprecated NuGet
Notifications Messaging Incubator NuGet
Cryptography Wrapper around IDataProtector Deprecated NuGet

About

A pragmatic set of .NET componentry addressing ordinary use cases for line-of-business application development.

Topics

Resources

License

Stars

Watchers

Forks

Contributors 5

Languages