Skip to content

Primitively is a powerful C# source generator that transforms primitive identifiers and value objects into highly performant, customisable, read-only struct values that support ASP.NET model binding and validation (including FluentValidation), Open API standards, JSON and MongoDB BSON serialization, with zero or minimal configuration.

License

Notifications You must be signed in to change notification settings

dtanglr/Primitively

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Primitively

Primitively CI

Primitively is a Rosyln-powered C# source code generator of strongly-typed IDs and DDD-style value objects that encapsulate a single GUID, integer, date or string .NET primitively typed value.

For example: -

// Before
public record Product(Guid Id, Guid Sku);

// After
public record Product(ProductId Id, Sku Sku);

[Guid]
public partial record struct ProductId;

[Guid]
public partial record struct Sku;

NuGet Packages

Package Latest Version About
Primitively NuGet The Primitively source generator package.
Primitively.Abstractions NuGet Primitively interfaces, metadata, attributes and configuration classes.
Primitively.AspNetCore.Mvc NuGet ASP.NET MVC model binding support for Primitively types used in route and querystring parameters.
Primitively.AspNetCore.SwaggerGen NuGet Swagger Open API schema support for Primitively types using Swashbuckle.
Primitively.FluentValidation NuGet FluentValidation support for Primitively types.
Primitively.MongoDB.Bson NuGet BSON serialization for Primitively types stored in MongoDB.

Documentation

This README is designed get you started generating your own strongly-typed identifiers with just a few lines of code.

For more detailed information about Primitively, check out primitively.net.

Quick start

To get started, first add the Primitively NuGet package to your project by running the following command:

dotnet add package Primitively

Open your csproj file and edit the package reference, setting PrivateAssets="All". The file will look something like this afterwards:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Primitively" Version="1.4.20" PrivateAssets="All" />
  </ItemGroup>
  
</Project>

You are now ready to create your first Primitively source generated type!

Create a new class file and add a reference to Primitively and decorate your partial record struct with one of the Primitively attributes such as [Guid].

For example: -

using Primitively;

namespace Acme.Examples;

[Guid]
public partial record struct ProductId;

Here's a list of all the Primitively attributes currently available: -

  • Date and time
    • [DateOnly]
  • Globally unique identifiers
    • [Guid]
  • Integers
    • [Byte]
    • [Int]
    • [Long]
    • [SByte]
    • [Short]
    • [UInt]
    • [ULong]
    • [UShort]
  • Floating-points (v1.5.x)
    • [Double]
    • [Single]
  • Strings
    • [String]

Here's some source generation in action using each of the above attributes: -

Primitively examples

Using Primitively on an ASP.NET core web project

If you want to use your Primitively types in an ASP.NET core web project. Add the Primitively.AspNetCore.Mvc NuGet package to your project by running the following command. It contains model binding support for your Primitively types, which means you can use your Primitively types in request parameters.

dotnet add package Primitively.AspNetCore.Mvc

If you are also generating swagger documentation for a web API. Add the Primitively.AspNetCore.SwaggerGen NuGet package to your project by running the following command.

dotnet add package Primitively.AspNetCore.SwaggerGen

When using FluentValidation to validate your web requests. Add the Primitively.FluentValidation NuGet package to your project by running the following command. It contains two extension methods which validate any Primitively type with zero DI configuration.

dotnet add package Primitively.FluentValidation

Dependency injection

Here's an example of the DI setup for a C# ASP.NET web api project that references a class library containing Primitively source generated types and is generating swagger documentation.

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

// Add primitively configuration
builder.Services.AddPrimitively(options =>
{
    // Register the location of source generated Primitively types within the application
    // NB. No need to use reflection to scan assemblies! Each class library that contains source
    // generated Primitively types also has a 'PrimitiveLibrary' static helper class. Meta data such
    // as type name, underlying data type, example value, min / max Length etc can then be obtained
    // from the PrimitiveRepository instance within each class library
    options.Register(Acme.Lib1.PrimitiveLibrary.Repository);
})
// Add AspNetCore Mvc model binding support for Primitively types used in APIs.  This means strongly typed
// Primitively types can easily be used as querystring and route params too etc
.AddMvc()
// Add Swashbuckle Open Api Schema Filter so Primitively types are fully supported in the API Swagger documentation 
.AddSwaggerGen();

Using Primitively with MongoDB

If you want to store your Primitively types in MongoDB they will need a BSON serializer. Add the Primitively.MongoDB.Bson NuGet package to your project by running the following command. It contains highly configurable BSON serialization support for your Primitively types.

dotnet add package Primitively.MongoDB.Bson

Dependency injection

Here's an example of the DI setup for a .NET core application that uses both MongoDB and Primitively.

var services = new ServiceCollection();

// Add primitively configuration
services.AddPrimitively(options =>
{
    // Register the location of source generated Primitively types within the application
    options.Register(Acme.Lib1.PrimitiveLibrary.Repository);
})
// Add MongoDB BsonSerializer configuration. This method also supports registering types individually. By default
// it will register a BSON serializer for each Primitively type in the PrimitivelyOptions registry.
// Any Primitively types that are IGuid primitives will be by default stored in Mongo as the default CSharpLegacy Base64
// strings unless overridden using the Bson serializer options
.AddBson();

Your MongoDB related Primitively types can be registered in this way as well: -

services.AddPrimitively()
    .AddBson(builder => builder.Register(Acme.Lib1.PrimitiveLibrary.Repository));

Or you can just register individual types rather than an entire library: -

services.AddPrimitively()
    .AddBson(builder => builder.Register<ProductId>());

Each Primitively type's BSON serializer can be configured individually. Here's an example of how to set the options for the BSON serializer used on all your Primitively IGuid types: -

services.AddPrimitively()
    .AddBson(builder => builder
        .Register(Acme.Lib1.PrimitiveLibrary.Repository)
        .Configure<BsonIGuidSerializerOptions>(options => options
            .GuidRepresentation = MongoDB.Bson.GuidRepresentation.Standard));

Next steps

To learn more about Primitively, go to primitively.net.

Examples

Sample applications that demonstrate scenarios in which Primitively is commonly used are available for learning purposes in the examples folder.

Licence

Licensed under the terms of the MIT License

About

Primitively is a powerful C# source generator that transforms primitive identifiers and value objects into highly performant, customisable, read-only struct values that support ASP.NET model binding and validation (including FluentValidation), Open API standards, JSON and MongoDB BSON serialization, with zero or minimal configuration.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published