{"id":13629359,"url":"https://github.com/lucasteles/Strongly","last_synced_at":"2025-04-17T09:33:23.918Z","repository":{"id":65064509,"uuid":"581647893","full_name":"lucasteles/Strongly","owner":"lucasteles","description":"💪🏾 A  strongly-typed domain values source-generator","archived":false,"fork":false,"pushed_at":"2024-05-17T17:32:28.000Z","size":3947,"stargazers_count":39,"open_issues_count":10,"forks_count":6,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-10T13:16:24.540Z","etag":null,"topics":["csharp","dotnet","source-generator","strongly-typed","typed","value-object"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lucasteles.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-12-23T20:36:32.000Z","updated_at":"2025-03-19T18:01:01.000Z","dependencies_parsed_at":"2024-08-01T22:52:02.559Z","dependency_job_id":null,"html_url":"https://github.com/lucasteles/Strongly","commit_stats":null,"previous_names":["lucasteles/stronglytypedid.extended"],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lucasteles%2FStrongly","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lucasteles%2FStrongly/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lucasteles%2FStrongly/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lucasteles%2FStrongly/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lucasteles","download_url":"https://codeload.github.com/lucasteles/Strongly/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249270694,"owners_count":21241399,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["csharp","dotnet","source-generator","strongly-typed","typed","value-object"],"created_at":"2024-08-01T22:01:08.483Z","updated_at":"2025-04-17T09:33:22.182Z","avatar_url":"https://github.com/lucasteles.png","language":"C#","funding_links":[],"categories":["Content","Source Generators"],"sub_categories":["49. [Strongly](https://ignatandrei.github.io/RSCG_Examples/v2/docs/Strongly) , in the [PrimitiveObsession](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#primitiveobsession) category","Functional Programming"],"readme":"# Strongly\n\n![Strongly logo](https://raw.githubusercontent.com/lucasteles/Strongly/master/logo.png)\n\n![Build status](https://github.com/lucasteles/Strongly/actions/workflows/BuildAndPack.yml/badge.svg)\n[![NuGet](https://img.shields.io/nuget/v/Strongly.svg)](https://www.nuget.org/packages/Strongly/)\n\nStrongly makes creating strongly-typed values as easy as adding an attribute! No\nmore [accidentally passing arguments in the wrong order to methods](https://andrewlock.net/using-strongly-typed-entity-ids-to-avoid-primitive-obsession-part-1/#an-example-of-the-problem) -\nStrongly uses .NET 6's compile-time incremental source generators to\ngenerate [the boilerplate](https://andrewlock.net/using-strongly-typed-entity-ids-to-avoid-primitive-obsession-part-2/#a-full-example-implementation)\nrequired to use strongly-typed IDs.\n\nSimply, [install the required package](#installing) add the `[Strongly]` attribute to a `struct` (in the `Strongly`\nnamespace):\n\n```csharp\nusing Strongly;\n \n[Strongly] // \u003c- Add this attribute to auto-generate the rest of the type\npublic partial struct FooId { }\n```\n\nand the source generator magically generates the backing code when you save the file! Use _Go to Definition_ to see the\ngenerated code:\n\n\u003cimg src=\"https://raw.githubusercontent.com/andrewlock/Strongly/master/docs/strongly_typed_id.gif\" alt=\"Generating a strongly-typed ID using the Strongly packages\"/\u003e\n\n\u003e Strongly requires requires [the .NET Core SDK v6.0.100 or greater](https://dotnet.microsoft.com/download/dotnet/6.0).\n\n## Installing\n\nTo use the the [Strongly NuGet package](https://www.nuget.org/packages/Strongly), install\nthe [Strongly](https://www.nuget.org/packages/Strongly) package into your project. Depending on which converters you\nimplement, you may need one or more of the following additional packages\n\n* [System.Text.Json](https://www.nuget.org/packages/System.Text.Json/) (optional, only required\n  if [generating a System.Text `JsonConverter`](https://andrewlock.net/using-strongly-typed-entity-ids-to-avoid-primitive-obsession-part-2/#creating-a-custom-jsonconverter)).\n  Note that in .NET Core apps, you will likely already reference this project via transitive dependencies.\n* [Newtonsoft.Json](https://www.nuget.org/packages/Newtonsoft.Json/) (optional, only required\n  if [generating a Newtonsoft `JsonConverter`](https://andrewlock.net/using-strongly-typed-entity-ids-to-avoid-primitive-obsession-part-2/#creating-a-custom-jsonconverter)).\n  Note that in some ASP.NET Core apps, you will likely already reference this project via transitive dependencies.\n* [Dapper](https://www.nuget.org/packages/Dapper/) (optional, only required\n  if [generating a type mapper](https://andrewlock.net/using-strongly-typed-entity-ids-to-avoid-primitive-obsession-part-3/#interfacing-with-external-system-using-strongly-typed-ids))\n* [EF Core](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore) (optional, only required\n  if [generating an EF Core ValueConverter](https://andrewlock.net/strongly-typed-ids-in-ef-core-using-strongly-typed-entity-ids-to-avoid-primitive-obsession-part-4/))\n* [Swagger Annotations](https://www.nuget.org/packages/Swashbuckle.AspNetCore.Annotations) (optional, only required\n  if [generating an Swagger Schema Filter](#openapiswagger-specification)\n\nTo install the packages, add the references to your _csproj_ file, for example by running\n\n```bash\ndotnet add package Strongly \n```\n\nThis adds a `\u003cPackageReference\u003e` to your project. You can additionally mark the package as `PrivateAssets=\"all\"`\nand `ExcludeAssets=\"runtime\"`.\n\n\u003e Setting `PrivateAssets=\"all\"` means any projects referencing this one will not also get a reference to the _Strongly_\n\u003e package. Setting `ExcludeAssets=\"runtime\"` ensures the _Strongly.Attributes.dll_ file is not copied to your build\n\u003e output (it is not required at runtime).\n\n```xml\n\n\u003cProject Sdk=\"Microsoft.NET.Sdk\"\u003e\n\n    \u003cPropertyGroup\u003e\n        \u003cOutputType\u003eExe\u003c/OutputType\u003e\n        \u003cTargetFramework\u003enet6.0\u003c/TargetFramework\u003e\n    \u003c/PropertyGroup\u003e\n\n    \u003c!-- Add the package --\u003e\n    \u003cPackageReference Include=\"Strongly\" Version=\"1.0.0\" PrivateAssets=\"all\" ExcludeAssets=\"runtime\"/\u003e\n    \u003c!-- --\u003e\n\n\u003c/Project\u003e\n```\n\n## Usage\n\nTo create a strongly-typed ID, create a `partial struct` with the desired name, and decorate it with the `[Strongly]`\nattribute, in the `Strongly` namespace:\n\n```csharp\nusing Strongly;\n\n[Strongly] // Add this attribute to auto-generate the rest of the type\npublic partial struct FooId { }\n```\n\nThis generates the \"default\" strongly-typed ID using a `Guid` backing field, a custom `TypeConverter`, and a\ncustom `JsonConverter` based on System.Text.Json.\n\n### Customising the converters\n\nYou can customise which converters to generate by using flags. For example, to generate a `TypeConverter`,\na `Newtonsoft.Json`, and an EF Core `ValueConverter`, use\n\n```csharp\nusing Strongly;\n\n[Strongly(converters: StronglyConverter.TypeConverter | StronglyConverter.SystemTextJson | StronglyConverter.EfValueConverter)] \npublic partial struct SystemTextJsonConverterId { }\n```\n\n### Using different types as a backing fields\n\nThe default strongly-typed ID uses a `Guid` backing field:\n\n```csharp\nusing Strongly;\n\n[Strongly]\npublic partial struct FooId { }\n\nvar id = new FooId(Guid.NewGuid());\n```\n\nYou can choose a different type backing field, by passing a value of the `StronglyBackingType` enum in the constructor.\n\n```csharp\nusing Strongly;\n\n[Strongly(backingType: StronglyBackingType.String)]\npublic partial struct FooId { }\n\nvar id = new FooId(\"my-id-value\");\n```\n\nCurrently supported values are `Guid` (the default), `int`, `long`,`decimal`,`BigInteger`, `MassTransit.NewId`\nand `string`.\n\n## Changing the defaults globally\n\nIf you wish to change the converters, backing types, or implementations used by default for _all_ the `[Strongly]`\n-decorated types in your project, you can use the assembly attribute `[StronglyDefaults]` to set all of these. For\nexample, the following sets the default converter to a whole project to `[SystemTextJson]`, and changes the default\nbacking-type to an `int`\n\n```csharp\n// Set the defaults for the project\n[assembly:StronglyDefaults(\n    backingType: StronglyType.Int,\n    converters: StronglyConverter.SystemTextJson)]\n\n[Strongly]\npublic partial struct OrderId { }\n\n[Strongly]\npublic partial struct UserId { } \n```\n\nThis is equivalent to setting these values manually on all the IDs:\n\n```csharp\n[Strongly(\n    backingType: StronglyType.Int,\n    converters: StronglyConverter.SystemTextJson)]\npublic partial struct OrderId { }\n\n[Strongly(\n     backingType: StronglyType.Int,\n    converters: StronglyConverter.SystemTextJson)]\npublic partial struct UserId { }\n```\n\n## EF Core - ValueConverter\n\nWhen you create a `Strongly` type with EF Converter, the type will have a nested `ValueConverter` class you can use on\nyour entity model definition\n\n```csharp\n[Strongly(StronglyType.String, StronglyConverter.EfValueConverter)]\npublic partial struct PhoneNumber\n{\n}\n\npublic class MyDbContext : DbContext\n{\n    protected override void OnModelCreating(ModelBuilder builder)\n    {\n        var customer = builder.Entity\u003cCustomer\u003e();\n        customer.Property(x =\u003e x.Phone).HasConversion\u003cPhoneNumber.EfValueConverter\u003e();\n    }\n}\n\n```\n\nIf you have lots of strongly type values you can use the package bellow to automatically set\nthe `Strongly ValueConverter` on all your entities [![NuGet](https://img.shields.io/nuget/v/Strongly.EFCore.svg)](https://www.nuget.org/packages/Strongly.EFCore/)\n\n\n```bash\ndotnet add package Strongly.EFCore\n```\n\nAfter installation you need to set it on yor `DbContextOptionsBuilder`\n\n```csharp\nservices\n    .AddDbContext\u003cAppDbContext\u003e(options =\u003e options\n        .UseStronglyTypeConverters()\n        /* ... */\n        )\n```\n\n## OpenApi/Swagger Specification\n\nIf you wish to use an ID in your Swagger models and want to have schema and model sample reflecting the value\nbacking-field\ntype you will need:\n\n- Install [Swagger Annotations](https://www.nuget.org/packages/Swashbuckle.AspNetCore.Annotations) `\u003e=5.0.0`\n- Enable annotation in swagger gen with `services.AddSwaggerGen(c =\u003e c.EnableAnnotations());`\n- Use the converter flag `StronglyConverter.SwaggerSchemaFilter` on the ID decorator. eg:\n    ```csharp\n    [Strongly(\n        backingType: StronglyType.Int,\n        converters: StronglyConverter.SwaggerSchemaFilter | StronglyConverter.SystemTextJson)]\n    public partial struct UserId { }\n    ```\n\n## Embedding the attributes in your project\n\nBy default, the `[Strongly]` attributes referenced in your application are contained in an external dll. It is also\npossible to embed the attributes directly in your project, so they appear in the dll when your project is built. If you\nwish to do this, you must do two things:\n\n1. Define the MSBuild constant `STRONGLY_TYPED_EMBED_ATTRIBUTES`. This ensures the attributes are embedded in your\n   project\n2. Add `compile` to the list of excluded assets in your `\u003cPackageReference\u003e` element. This ensures the attributes in\n   your project are referenced, instead of the _Strongly.Attributes.dll_ library.\n\nYour project file should look something like this:\n\n```xml\n\n\u003cProject Sdk=\"Microsoft.NET.Sdk\"\u003e\n\n    \u003cPropertyGroup\u003e\n        \u003cOutputType\u003eExe\u003c/OutputType\u003e\n        \u003cTargetFramework\u003enet6.0\u003c/TargetFramework\u003e\n        \u003c!--  Define the MSBuild constant    --\u003e\n        \u003cDefineConstants\u003eSTRONGLY_TYPED_EMBED_ATTRIBUTES\u003c/DefineConstants\u003e\n    \u003c/PropertyGroup\u003e\n\n    \u003c!-- Add the package --\u003e\n    \u003cPackageReference Include=\"Strongly\" Version=\"1.0.0\"\n                      PrivateAssets=\"all\"\n                      ExcludeAssets=\"compile;runtime\"/\u003e\n    \u003c!--                               ☝ Add compile to the list of excluded assets. --\u003e\n\n\u003c/Project\u003e\n```\n\n## Preserving usages of the `[Strongly]` attribute\n\nThe `[Strongly]` and `[StronglyDefaults]` attributes are decorated with the `[Conditional]`\nattribute, [so their usage will not appear in the build output of your project](https://andrewlock.net/conditional-compilation-for-ignoring-method-calls-with-the-conditionalattribute/#applying-the-conditional-attribute-to-classes).\nIf you use reflection at runtime on one of your IDs, you will not find `[Strongly]` in the list of custom attributes.\n\nIf you wish to preserve these attributes in the build output, you can define the `STRONGLY_TYPED_USAGES` MSBuild\nvariable. Note that this means your project will have a runtime-dependency on _Strongly.Attributes.dll_ so you need to\nensure this is included in your build output.\n\n```xml\n\n\u003cProject Sdk=\"Microsoft.NET.Sdk\"\u003e\n\n    \u003cPropertyGroup\u003e\n        \u003cOutputType\u003eExe\u003c/OutputType\u003e\n        \u003cTargetFramework\u003enet6.0\u003c/TargetFramework\u003e\n        \u003c!--  Define the MSBuild constant to preserve usages   --\u003e\n        \u003cDefineConstants\u003eSTRONGLY_TYPED_USAGES\u003c/DefineConstants\u003e\n    \u003c/PropertyGroup\u003e\n\n    \u003c!-- Add the package --\u003e\n    \u003cPackageReference Include=\"Strongly\" Version=\"1.0.0\" PrivateAssets=\"all\"/\u003e\n    \u003c!--              ☝ You must not exclude the runtime assets in this case --\u003e\n\n\u003c/Project\u003e\n```\n\n## Why do I need this library?\n\nAndrew\nhave [written a blog-post series](https://andrewlock.net/using-strongly-typed-entity-ids-to-avoid-primitive-obsession-part-1/)\non strongly-typed IDs that explains the issues and rational behind this library. For a detailed view, I suggest starting\nthere, but I provide a brief introduction here.\n\nThis library is designed to tackle a specific instance of [_primitive\nobsession_](https://lostechies.com/jimmybogard/2007/12/03/dealing-with-primitive-obsession/), whereby we use primitive\nobjects (`Guid`/`string`/`int`/`long`/`decimal` etc) to represent the IDs or values of\ndomain objects. The problem is that these\ntypes are all\ninterchangeable - an order ID can be assigned to a product ID despite the fact that is likely nonsensical from the\ndomain point of\nview. [See here for a more concrete example](https://andrewlock.net/using-strongly-typed-entity-ids-to-avoid-primitive-obsession-part-1/#an-example-of-the-problem).\n\nBy using strongly-typed values, we give each of then its own `Type` which _wraps_ the underlying primitive value. This\nensures\nyou can only use the value where it makes sense: `ProductId`s can only be assigned to products, or you can only search\nfor\nproducts using a `ProductId`, not an `OrderId`.\n\nUnfortunately, taking this approach\nrequires [a lot of boilerplate and ceremony](https://andrewlock.net/using-strongly-typed-entity-ids-to-avoid-primitive-obsession-part-2/#a-full-example-implementation)\nto make working with it manageable. This library abstracts all that away from you, by generating the boilerplate at\nbuild-time by using a Roslyn-powered code generator.\n\n## What code is generated?\n\nThe exact code generated depends on the arguments you provide to the `Strongly` attribute. The code is generated to the\n_obj_ folder of the project, so you can use _Go to Definition_ on your Id to see the _exact_ code generated in each\ncase.\n\n## Requirements\n\nThe Strongly NuGet package is a .NET Standard 2.0 package.\n\nYou must be using the .NET 6+ SDK (though you can compile for other target frameworks like .NET Core 2.1 and .NET\nFramework 4.8)\n\nThe `struct`s you decorate with the `Strongly` attribute must be marked `partial`.\n\n## Credits\n\n[Credits]: #credits\n\nThis project born as a fork of [StronglyTypedId](https://github.com/andrewlock/StronglyTypedId) \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flucasteles%2FStrongly","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flucasteles%2FStrongly","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flucasteles%2FStrongly/lists"}