Skip to content

VcsCheckEnabled has no effect on a project that applies no aspect #113

Description

Summary

The source control check enabled by VcsCheckEnabled does not run on a project that applies no aspect to its own code. The build fails with PS0242 even when every source file of the project is unmodified in version control. The licensing trace contains no record that the check was attempted.

Conditions

Both of these conditions must be met at the same time:

  1. No valid license key is available on the machine. The registry, postsharp.config, the LicenseKeys property and any configured license server contain no key that is valid for the PostSharp version being built. An expired key has the same effect as no key at all.
  2. The project applies no aspect to its own code. Defining an aspect type is not sufficient to avoid this condition: the aspect must be applied to a declaration of the project, whether directly, by multicast, or by inheritance.

The state of the working tree does not matter. The check never runs, so a clean working tree gives the same result as a modified one. This is why setting VcsCheckEnabled to True appears to have no effect.

Scope

There are two reasons to reference PostSharp from a project: to define aspects, or to use them. Only the second one weaves anything into the project itself.

Condition 2 is therefore met by every project that defines aspects for other projects to use. An aspect library fails to build, even though its own source files are unmodified.

Condition 2 is also met by a project that references PostSharp but neither defines nor uses an aspect. This happens in a large solution when the reference arrives from a shared import such as Directory.Build.props or a solution-wide package reference.

The feature is documented to let a developer build unmodified code without consuming a license seat. For the projects described above, it does not.

Expected behavior

When VcsCheckEnabled is set to True and the source files of the project are unmodified in version control, the project builds successfully, whether or not it applies an aspect.

Actual behavior

The build fails with:

error PS0242: License error. No valid license key has been installed. To register a license key, see https://doc.postsharp.net/deploying-keys.

When the build runs with -p:PostSharpTrace=Licensing at detailed verbosity, the trace contains none of the three lines that the source control check writes:

  • The project is not modified.
  • The project is modified: ...
  • VCS check was not performed because ...

The absence of all three lines means that the check was not attempted. It does not mean that the check ran and refused.

Steps to reproduce

  1. Create a class library that defines an aspect and does not apply it to any declaration of the project.
  2. Add a postsharp.config file with <Property Name="VcsCheckEnabled" Value="True" />.
  3. Commit the project to a git repository and leave the working tree clean.
  4. Make sure that no license key is registered on the machine.
  5. Build the project interactively.

The build fails with PS0242.

Workaround

Any license key that covers PostSharp Essentials satisfies the requirement that fails, because the failing check accepts any user license.

Root cause

The Unmodified license is created as a side effect of aspect weaving. For each woven aspect instance, AspectWeaverInstance calls LocalLicenseManager.RequireLicensedFeaturesForWeavedInstance. That call reaches IsRequirementSatisfiedByAssembly, which calls CheckVcs. CheckVcs runs git status --porcelain and, when the source files of the project are unmodified, registers the Unmodified license with SharedUserLicenseManager.

Project.CheckUserLicensePresent runs before the Generate phase and requires LicensedPackages.Essentials from a user license. It reads the license collection, but it never triggers the source control check itself. When no aspect instance is woven, nothing registers the Unmodified license, so the requirement fails and PS0242 is reported.

The Unattended license does not have this problem. SharedUserLicenseManager.TrySatisfyRequirement registers it on demand, on the same code path that CheckUserLicensePresent takes. This is why a continuous integration build of the same project succeeds while an interactive build of it fails.

Suggested fix

Register the Unmodified license on demand, in the same way as the Unattended license, so that CheckUserLicensePresent can satisfy its requirement from the source control check. This grants only what VcsCheckEnabled already promises, so it does not change licensing policy.

Note for investigation

There may be a second way to meet condition 2, which has not been verified. In IsRequirementSatisfiedByAssembly, an embedded license found in the aspect assembly returns before CheckVcs is called. Only the Framework package can be satisfied that way, so a project that uses the Pattern Libraries is not affected, because it also requires Logging, Threading or Caching. A project whose aspects come entirely from a library with an embedded redistribution license, and which requires nothing beyond Framework, may therefore behave in the same way. This should be confirmed before the fix is scoped.

Versions

The behavior described here was verified on the 2024.0 development line. The original report came from a customer on 2026.0.12, and the same behavior is expected there, but it has not yet been confirmed on that line.

— Claude for Gael

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions