PosInformatique.Foundations.People 1.1.0

Prefix Reserved
There is a newer prerelease version of this package available.
See the version list below for details.
dotnet add package PosInformatique.Foundations.People --version 1.1.0
                    
NuGet\Install-Package PosInformatique.Foundations.People -Version 1.1.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="PosInformatique.Foundations.People" Version="1.1.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="PosInformatique.Foundations.People" Version="1.1.0" />
                    
Directory.Packages.props
<PackageReference Include="PosInformatique.Foundations.People" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add PosInformatique.Foundations.People --version 1.1.0
                    
#r "nuget: PosInformatique.Foundations.People, 1.1.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package PosInformatique.Foundations.People@1.1.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=PosInformatique.Foundations.People&version=1.1.0
                    
Install as a Cake Addin
#tool nuget:?package=PosInformatique.Foundations.People&version=1.1.0
                    
Install as a Cake Tool

PosInformatique.Foundations.People

NuGet version NuGet downloads

Introduction

This package provides lightweight, strongly-typed value objects to standardize first names and last names across your applications:

  • FirstName: normalized, properly cased first names.
  • LastName: normalized, fully uppercased last names.

It also includes:

  • IPerson: a small interface to represent nominative people with FirstName and LastName.
  • Extension methods on IPerson for consistent display/order names and initials.
  • NameNormalizer: helper methods when you only have the separated first/last names.

Typical use cases: domain entities (User, Customer, Employee, Contact), consistent UI display (Blazor components, lists), alphabetical ordering (directories), and avatar initials.

Install

You can install the package from NuGet:

dotnet add package PosInformatique.Foundations.People

Features

  • Strongly-typed FirstName and LastName with validation and normalization
  • Business rules:
    • FirstName: title-cased words; letters only; separators: space, hyphen
    • LastName: fully uppercased; letters only; separators: space, hyphen
    • No consecutive/trailing separators; max length 50
  • Acts like read-only char arrays: indexer and Length
  • Implements IParsable<T>, IFormattable, IComparable<T>, IEquatable<T>
  • Implicit conversions to/from string
  • IPerson interface for nominative person abstraction
  • PersonExtensions for display name, ordering name, and initials
  • NameNormalizer utilities for first/last names without IPerson

Business rules

FirstName

  • Max length: 50.
  • Allowed characters: letters only; separators: ' ' and '-'.
  • Normalization:
    • Each word starts uppercase and continues lowercase (e.g., "John", "John Henri-Smith").
    • No consecutive separators, ths trailing separators are removed.

LastName

  • Max length: 50.
  • Allowed characters: letters only; separators: ' ' and '-'.
  • Normalization:
    • Entire value uppercased (e.g., "DOE", "SMITH-JOHNSON").
    • No consecutive separators, the trailing separators are removed.

FirstName examples

Create / implicit conversion
// Implicit conversion validates and normalizes:
FirstName firstName = "john  henri-smith";   // -> "John Henri-Smith"

// Explicit create:
var firstName2 = FirstName.Create("  alice--marie "); // -> "Alice-Marie"

// IsValid
var ok = FirstName.IsValid("Élodie");       // true
var notOk = FirstName.IsValid("John_123");  // false
Parse / TryParse
// Parse (throws on invalid)
var firstName = FirstName.Parse("béAtrice", provider: null); // "Béatrice"

// TryParse (no exceptions)
if (FirstName.TryParse("jeAn  -  pierre", provider: null, out var firstName))
{
    Console.WriteLine(firstName); // "Jean-Pierre"
}
Length and indexer
var firstName = FirstName.Create("Jean-Pierre");
var len = firstName.Length;     // 11
var firstLetter = firstName[0]; // 'J'
var dash = firstName[4];        // '-'

// Enumerate characters
foreach (var c in firstName) { /* ... */ }
Comparisons and equality
var a = FirstName.Create("Alice");
var b = FirstName.Create("ALICE");   // normalized: "Alice"

Console.WriteLine(a == b);  // true
Console.WriteLine(a != b);  // false
Console.WriteLine(a <= b);  // true
Console.WriteLine(a.CompareTo(b)); // 0

var list = new List<FirstName> { FirstName.Create("Zoé"), FirstName.Create("Ana") };
list.Sort(); // alphabetical by normalized value

LastName examples

Create / implicit conversion
LastName lastName = "dupond  durand";  // -> "DUPOND DURAND"
var lastName2 = LastName.Create("le--gall"); // -> "LE GALL"
var ok = LastName.IsValid("O'Connor"); // false (apostrophe not allowed)
Parse / TryParse
var parsed = LastName.Parse("martin", provider: null); // "MARTIN"

if (LastName.TryParse("van  -  damme", provider: null, out var lastName))
{
    Console.WriteLine(lastName); // "VAN DAMME"
}
Length and indexer
var lastName = LastName.Create("LE GALL");
var len = lastName.Length;     // 7
var firstLetter = lastName[0]; // 'L'
var space = lastName[2];       // ' '

// Enumerate characters
foreach (var c in lastName) { /* ... */ }
Comparisons and equality
var a = LastName.Create("DURAND");
var b = LastName.Create("durand"); // normalized to "DURAND"

Console.WriteLine(a == b);  // true
Console.WriteLine(a < LastName.Create("MARTIN")); // true

var list = new List<LastName> { LastName.Create("ZOLA"), LastName.Create("ABEL") };
list.Sort(); // alphabetical by normalized value

IPerson

IPerson represents a nominative person with a normalized FirstName and LastName. Implement this in domain types like User, Customer, Employee, Contact.

public sealed class User : IPerson
{
    public User(FirstName firstName, LastName lastName)
    {
        FirstName = firstName;
        LastName = lastName;
    }

    public FirstName FirstName { get; }
    public LastName LastName { get; }
}

You can also accept string and normalize:

public sealed class Customer : IPerson
{
    public Customer(string firstName, string lastName)
    {
        // Implicit conversions validate and normalize
        FirstName = firstName;
        LastName = lastName;
    }

    public FirstName FirstName { get; }
    public LastName LastName { get; }
}

PersonExtensions

Utilities for consistent display, ordering, and initials on any IPerson.

  • GetFullNameForDisplay(): "First-Name LASTNAME" (e.g., "John DOE"). Use in UI display (e.g., Blazor component).
  • GetFullNameForOrder(): "LASTNAME First-Name" (e.g., "DOE John"). Use for alphabetical directories by last name.
  • GetInitials(): first letter of FirstName + first letter of LastName (e.g., "JD"). Use as fallback when avatar image is not available.

Examples:

var user = new User("jean-paul", "dupont");

var display = user.GetFullNameForDisplay(); // "Jean-Paul DUPONT"
var order = user.GetFullNameForOrder();     // "DUPONT Jean-Paul"
var initials = user.GetInitials();          // "JD"

Blazor example:

@code {
    [Parameter] public IPerson Person { get; set; } = default!;
}
<h3>@Person.GetFullNameForDisplay()</h3>
<span class="avatar">@Person.GetInitials()</span>

Sorting by order name:

var people = new List<IPerson>
{
    new User("alice", "martin"),
    new User("bob", "durand"),
    new User("Élodie", "zola")
};

var ordered = people
    .OrderBy(p => p.GetFullNameForOrder(), StringComparer.Ordinal)
    .ToList();
// "DURAND Bob", "MARTIN Alice", "ZOLA Élodie"

NameNormalizer

When you only have separate FirstName and LastName (not an IPerson), use NameNormalizer.

  • GetFullNameForDisplay(firstName, lastName) ⇒ "First-Name LASTNAME"
  • GetFullNameForOrder(firstName, lastName) ⇒ "LASTNAME First-Name"

Examples:

var firstName = FirstName.Create("marie-claire");
var lastName = LastName.Create("le gall");

var display = NameNormalizer.GetFullNameForDisplay(firstName, lastName); // "Marie-Claire LE GALL"
var order = NameNormalizer.GetFullNameForOrder(firstName, lastName);     // "LE GALL Marie-Claire"

Error handling tips

  • Use TryParse / TryCreate when you want to avoid exceptions:
if (FirstName.TryParse(inputFirstName, null, out var firstName) &&
    LastName.TryParse(inputLastName, null, out var lastName))
{
    var user = new User(firstName, lastName);
}
else
{
    // handle invalid inputs
}
Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net10.0

    • No dependencies.
  • net8.0

    • No dependencies.
  • net9.0

    • No dependencies.

NuGet packages (6)

Showing the top 5 NuGet packages that depend on PosInformatique.Foundations.People:

Package Downloads
PosInformatique.Foundations.People.EntityFramework

Provides Entity Framework Core integration for the FirstName and LastName value objects from PosInformatique.Foundations.People. Offers fluent configuration helpers and converters to map normalized first and last names as NVARCHAR(50) columns with proper value conversion and comparison.

PosInformatique.Foundations.People.FluentValidation

Provides FluentValidation extensions to validate first and last names using the strongly-typed FirstName and LastName value objects from PosInformatique.Foundations.People.

PosInformatique.Foundations.People.FluentAssertions

Provides FluentAssertions extensions for FirstName and LastName value objects from PosInformatique.Foundations.People, resolving the Should() ambiguity and enabling idiomatic assertions like Should().Be(string) on normalized values.

PosInformatique.Foundations.People.Json

Provides System.Text.Json converters for the FirstName and LastName value objects. Enables seamless serialization and deserialization of validated person names within JSON documents.

PosInformatique.Foundations.People.DataAnnotations

Provides DataAnnotations attributes to validate first and last names using the strongly-typed FirstName and LastName value objects from PosInformatique.Foundations.People.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.2.0-rc.1 100 3/31/2026
1.1.0 236 3/30/2026
1.1.0-rc.3 86 3/27/2026
1.1.0-rc.2 84 1/26/2026
1.1.0-rc.1 101 1/23/2026
1.0.0 575 11/19/2025
1.0.0-rc.4 403 11/19/2025
1.0.0-rc.3 395 11/18/2025
1.0.0-rc.2 395 11/18/2025
1.0.0-rc.1 394 11/18/2025
Loading failed

1.0.0
 - Initial release with strongly-typed FirstName, LastName value objects.
 - Add IPerson interface + extension methods
 - NameNormalizer to normalize the composed names first name / last name