ThisAssembly

repository·main·Indexed 19 days ago

https://github.com/devlooped/thisassembly

A suite of Roslyn source generators that expose MSBuild, Git, and assembly metadata as type-safe, compile-time C# constants. Includes specialized packages for assembly attributes (AssemblyInfo), custom MSBuild constants (Constants), Git properties (Git), arbitrary assembly metadata (Metadata), project properties (Project), embedded resources (Resources), .resx files (Strings), and VSIX manifest metadata (Vsix).

Tokens
8.2K
Snippets
25
Records
39
Agent score
63%

What's inside ThisAssembly

  1. Overview of ThisAssembly

    main

    ThisAssembly is a collection of Roslyn-powered source generators that expose project and assembly-level information as C# constants. The primary entry point is a partial class named ThisAssembly located in the global namespace (by default), which can be extended with manual members.

    Key features:

    • Exposes assembly attributes, Git information, MSBuild constants, and project metadata as type-safe C# constants.
    • Uses the $(ThisAssemblyNamespace) MSBuild property to customize the root namespace.
    • Each specialized package extends the ThisAssembly partial class to add its own nested types and members.
    • For convenience, the ThisAssembly meta-package includes all individual packages.
    // The generated class is partial, allowing you to add your own members
    public partial class ThisAssembly
    {
        public static void MyManualMethod() { }
    }
  2. Use ThisAssembly.AssemblyInfo to access assembly metadata

    main

    The ThisAssembly.AssemblyInfo package automatically generates a static ThisAssembly.Info class for SDK-style projects. This class provides public constants that allow you to access assembly attributes directly in your code without using reflection.

    By default, the following attributes are exposed as constants:

    • AssemblyConfigurationAttribute
    • AssemblyCompanyAttribute
    • AssemblyTitleAttribute
    • AssemblyDescriptionAttribute
    • AssemblyProductAttribute
    • AssemblyCopyrightAttribute
    • AssemblyVersionAttribute
    • AssemblyInformationalVersionAttribute
    • AssemblyFileVersionAttribute

    If your project already defines these attributes through other means (such as in your .csproj file), they will still be correctly emitted and accessible on the ThisAssembly.Info class.

  3. Use ThisAssembly.Strings for type-safe string resources

    main

    The ThisAssembly.Strings package generates a static class that exposes string resources from .resx files as public constants or methods.

    Key Features:

    • Type-safe Formatting: If a resource contains format placeholders (e.g., {0}), the generator creates a method with the exact number of parameters required to satisfy the format string.
    • Nested Organization: Strings are automatically grouped into nested classes based on an underscore (_) separator in the resource name. For example, a resource named Shopping_NoShipping becomes accessible via ThisAssembly.Strings.Shopping.NoShipping().
    • Named Format Support: The generator can handle specific date formats (e.g., {date:yyyy-MM}) by replacing them with standard format strings and applying the appropriate formatting to the passed argument.
    // Example usage based on generated code
    string log = ThisAssembly.Strings.Infrastructure.MissingService("AuthService");
    string msg = ThisAssembly.Strings.Shopping.NoShipping("Item", "Location");
    string status = ThisAssembly.Strings.Shopping.OutOfStock;
  4. Use ThisAssembly.Strings for localized and formatted strings

    main

    The ThisAssembly.Strings package generates a static ThisAssembly.Strings class from .resx files.

    • Organization: Strings are grouped into nested classes using an underscore (_) as a separator. For example, User_InvalidCredentials becomes ThisAssembly.Strings.User.InvalidCredentials.
    • Constants vs Methods:
      • Simple strings are exposed as public static string properties.
      • Strings containing format placeholders (e.g., {0}) are exposed as methods with the appropriate number of parameters.
    • Formatting: The generated methods use string.Format with CultureInfo.CurrentCulture.
    // If Resx has: Shopping_NoShipping = "We cannot ship {0} to {1}."
    string msg = ThisAssembly.Strings.Shopping.NoShipping("New York", "London");
    
    // If Resx has: Shopping_OutOfStock = "Product is out of stock."
    string msg2 = ThisAssembly.Strings.Shopping.OutOfStock;
  5. Compare Default vs Public visibility modes

    main

    The way ThisAssembly.Constants are exposed depends on the $(ThisAssemblyVisibility) setting:

    1. Default (Internal): Uses const. This is optimal for performance as the compiler inlines values directly into the call site.
    2. Public: Uses static readonly properties. This allows consuming code to use updated values from a referenced assembly without requiring a recompile.
    // Default (Internal)
    partial class ThisAssembly
    {
        public partial class Constants
        {
            public const string Hello = "World";
        }
    }
    
    // Public
    public partial class ThisAssembly
    {
        public partial class Constants
        {
            public static string Hello => "World";
        }
    }
  6. Use ThisAssembly.Git to access Git metadata

    main

    The ThisAssembly.Git package generates a static ThisAssembly.Git class containing constants for Git properties extracted from the current project. This allows you to embed versioning and source information directly into your application code.

    Available properties include:

    • Commit: The full commit hash.
    • Sha: The first 9 characters of the commit hash.
    • Root: The repository root path (normalized to forward slashes).
    • Url: The repository URL (available if PublishRepositoryUrl is set to true).
    • Branch: The current branch name, populated from CI environment variables (e.g., GitHub Actions, Azure DevOps, GitLab CI, etc.).

    Note on CI Branches: When a CI system provides a pull request number, the Branch property is formatted as pr[NUMBER] (e.g., pr123), which is useful for semver metadata.

  7. Configure ThisAssembly.Git for GitHub and NuGet packaging

    main

    To automatically populate NuGet package metadata with Git information, use ThisAssembly.Git alongside Microsoft.SourceLink and NuGetizer.

    For a GitHub repository, add the following package references to your project file. Note that for .NET 8 SDK and later, Microsoft.SourceLink is included by default and does not need to be added manually.

    <Project Sdk="Microsoft.NET.Sdk">
      <PropertyGroup>
        <TargetFramework>netstandard2.0</TargetFramework>
      </PropertyGroup>
    
      <ItemGroup>
        <PackageReference Include="Microsoft.SourceLink.GitHub" />
        <PackageReference Include="ThisAssembly.Git" />
        <PackageReference Include="NuGetizer" />
      </ItemGroup>
    </Project>
  8. Use ThisAssembly.Metadata to access assembly metadata

    main

    The ThisAssembly.Metadata package provides a static class containing public constants that expose metadata defined in your project file. This allows you to access [System.Reflection.AssemblyMetadata] attributes as strongly-typed constants in your C# code instead of using reflection at runtime.

    To make a piece of metadata available via this package, you must define it in your project file using MSBuild syntax with the <AssemblyMetadata> item.

    <!-- In your .csproj file -->
    <ItemGroup>
      <AssemblyMetadata Include="Foo" Value="Bar" />
    </ItemGroup>
    
    // In your C# code
    string value = ThisAssembly.Metadata.Foo;
    // value is "Bar"
  9. Expose MSBuild properties as C# constants with ThisAssembly.Project

    main

    The ThisAssembly.Project package automatically generates a static C# class named ThisAssembly.Project. This class contains public constants that expose MSBuild properties from your project file.

    To include a property in the generated class, you must explicitly opt-in by adding it as a ProjectProperty item in your .csproj file. You can optionally provide a Comment attribute to customize the XML comment associated with the generated constant.

    <PropertyGroup>
      <!-- Some arbitrary MSBuild property declared somewhere -->
      <Foo>Bar</Foo>
    </PropertyGroup>
    
    <ItemGroup>
      <!-- Opt-in to emitting that property value as a constant in ThisAssembly.Project -->
      <ProjectProperty Include="Foo" Comment="This comment replaces the default comment :)" />
    </ItemGroup>
  10. Generate C# constants using ThisAssembly.Constants

    main

    The ThisAssembly.Constants package generates a static ThisAssembly.Constants class containing public constants based on MSBuild <Constant> items defined in your project file.

    Each <Constant> item supports the following attributes:

    • Include: The name of the constant (using dot notation for nesting, e.g., Foo.Bar).
    • Value: The value assigned to the constant. This can be a literal or an MSBuild property (e.g., $(MyProperty)).
    • Type: (Optional) The C# type for the constant (e.g., int, bool, long, double). If omitted, string is assumed.
    • Comment: (Optional) A documentation comment to be included in the generated code.

    Values can be multi-line; if the target language version is C# 11 or higher, the generated code will use C# raw string literals.

    <ItemGroup>
      <Constant Include="Foo.Bar" Value="Baz" Comment="Yay!" />
      <Constant Include="Foo.Hello" Value="World" Comment="Comments make everything better 😍" />
    </ItemGroup>
  11. Use CI builds for testing and dogfooding

    main

    You can use CI packages produced from branches and pull requests to test builds as they are generated. The CI feed is available at https://pkg.kzu.app/index.json.

    Package versions follow these schemes:

    • PR builds: 42.42.42-pr[NUMBER]
    • Branch builds: 42.42.42-[BRANCH].[COMMITS]
    # Use the CI feed
    https://pkg.kzu.app/index.json