Report codes are chosen to conform to suggested guidelines. Those guidelines are currently in revew: #10088
Diagnostic Code | Default Severity | Default Scope | Available from SDK | Reason |
---|---|---|---|---|
BC0101 | Warning | N/A | 9.0.100 | Shared output path. |
BC0102 | Warning | N/A | 9.0.100 | Double writes. |
BC0103 | Suggestion | Project | 9.0.100 | Used environment variable. |
BC0104 | Warning | N/A | 9.0.200 | ProjectReference is preferred to Reference. |
BC0105 | Warning | N/A | 9.0.200 | Culture specific EmbeddedResource should specify Culture metadata. |
BC0106 | Warning | N/A | 9.0.200 | CopyToOutputDirectory='Always' should be avoided. |
BC0107 | Warning | N/A | 9.0.200 | TargetFramework and TargetFrameworks specified together. |
BC0108 | Warning | N/A | 9.0.300 | TargetFramework or TargetFrameworks specified in non-SDK style project. |
BC0109 | Warning | N/A | 9.0.300 | Building using the Exec task. |
BC0201 | Warning | Project | 9.0.100 | Usage of undefined property. |
BC0202 | Warning | Project | 9.0.100 | Property first declared after it was used. |
BC0203 | None | Project | 9.0.100 | Property declared but never used. |
BC0301 | None | Project | 9.0.300 | Building from Downloads folder. |
Notes:
- What does the 'N/A' scope mean? The scope of checks are only applicable and configurable in cases where evaluation-time data are being used and the source of the data is determinable and available. Otherwise the scope of whole build is always checked.
- How can you alter the default configuration? Please check the Configuration section of the BuildCheck documentation
- To enable verbose logging in order to troubleshoot issue(s), enable [binary logging](https://github.com/dotnet/msbuild/blob/main/documentation/wiki/Binary-Log.md#msbuild-binary-log-overview
Cmd:
dotnet build -bl -check
"Two projects should not share their OutputPath nor IntermediateOutputPath locations"
It is not recommended to share output path nor intermediate output path between multiple projects. Such practice can lead to silent overwrites of the outputs. Such overwrites will depend on the order of the build, that might not be guaranteed (if not explicitly configured) and hence it can cause nondeterministic behavior of the build.
If you want to produce outputs in a consolidated output folder - consider using the Artifacts output layout and/or Microsoft.Build.Artifacts SDK.
"Two tasks should not write the same file"
This is a similar problem as 'BC0101 - Shared output path' - however with higher granularity. It is not recomended that multiple tasks attempt to write to a single file - as such behavior might lead to nondeterminism of a build (as result can be dependent on the order of the tasks execution if those belong to independent projects) or/and to a lost updates.
If you want multiple tasks to update file in a one-by-one pipeline fashion, it is recommended to give each intermediate output a distinct name - preventing silent mixups if any of the tasks in the chain are skipped or removed.
"Environment variables should not be used as a value source for the properties"
Using environment variables as a data source in MSBuild is problematic and can lead to nondeterministic builds. Relying on environment variables introduces variability and unpredictability, as their values can change between builds or environments.
This practice can result in inconsistent build outcomes and makes debugging difficult, since environment variables are external to project files and build scripts. To ensure consistent and reproducible builds, avoid using environment variables. Instead, explicitly pass properties using the /p option, which offers better control and traceability.
"A project should not be referenced via 'Reference' to its output, but rather directly via 'ProjectReference'."
It is not recommended to reference project outputs. Such practice leads to losing the explicit dependency between the projects. Build then might not order the projects properly, which can lead to randomly missing reference and hence undeterministic build.
If you need to achieve more advanced dependency behavior - check Controlling Dependencies Behavior document. If neither suits your needs - then you might need to disable this check for your build or for particular projects.
"It is recommended to specify explicit 'Culture' metadata, or 'WithCulture=false' metadata with 'EmbeddedResource' item in order to avoid wrong or nondeterministic culture estimation."
EmbeddedResource
item has a Culture
and WithCulture
metadata that are strongly recommended to be used - to prevent MSBuild to need to 'guess' the culture from the file extension - which may be dependent on the current OS/Runtime available cultures and hence it can lead to nondeterministic build.
Examples:
<EmbeddedResource Update = "Resource1.xyz.resx" Culture="xyz" />
This indicates the culture to the MSBuild engine and the culture will be respected. No diagnostic (warning) is issued (see below for exceptions).<EmbeddedResource Update = "Resource1.xyz.resx" WithCulture="false" />
This indicates to the MSBuild engine that the file is culture neutral and the extension should not be treated as culture indicator. No diagnostic (warning) is issued.<EmbeddedResource Update = "Resource1.xyz.resx" />
MSBuild infers the culture from the extra extension ('xyz') and if it is known toSystem.Globalization.CultureInfo
it is being used as the resource culture. TheBC0105
diagnostic is emitted (if BuildCheck is enabled and BC0105 is not disabled)<EmbeddedResource Update = "Resource1.resx" />
MSBuild infers that the resource is culture neutral. No diagnostic (warning) is issued.
Note: In Full Framework version of MSBuild (msbuild.exe, Visual Studio) and in .NET SDK prior 9.0 a global or project specific property RespectAlreadyAssignedItemCulture
needs to be set to 'true'
in order for the explicit Culture
metadata to be respected. Otherwise the explicit culture will be overwritten by MSBuild engine and if different from the extension - a MSB3002
warning is emitted ("MSB3002: Explicitly set culture "{0}" for item "{1}" was overwritten with inferred culture "{2}", because 'RespectAlreadyAssignedItemCulture' property was not set."
)
"Avoid specifying 'Always' for 'CopyToOutputDirectory' as this can lead to unnecessary copy operations during build. Use 'PreserveNewest' or 'IfDifferent' metadata value, or set the 'SkipUnchangedFilesOnCopyAlways' property to true to employ more effective copying."
CopyToOutputDirectory
metadata can take the values:
Never
Always
PreserveNewest
IfDifferent
Always
is not recommended, as it causes the files to be copied in every build, even when the destination file content is identical to the source.
Before the introduction of IfDifferent
, Always
was needed to work around cases where the destination file could have changed between builds (e.g. an asset that can be changed during test run, but needs to be reset by the build). IfDifferent
preserves this behavior without unnecessary copying.
In order to avoid the need to change copy metadata for a large number of items, it's now possible to specify the SkipUnchangedFilesOnCopyAlways
property in order to flip all copy behavior of CopyToOutputDirectory=Always
to behave identically to CopyToOutputDirectory=IfDifferent
:
<PropertyGroup>
<SkipUnchangedFilesOnCopyAlways>True</SkipUnchangedFilesOnCopyAlways>
</PropertyGroup>
<ItemGroup>
<None Include="File1.txt" CopyToOutputDirectory="Always" />
<None Include="File2.txt" CopyToOutputDirectory="IfDifferent" />
</ItemGroup>
Both items in above example are treated same and no BC0106 diagnostic is issued.
"'TargetFramework' (singular) and 'TargetFrameworks' (plural) properties should not be specified in the scripts at the same time."
When building a .NET project - you can specify target framework of the resulting output (for more info see the documentation).
When using TargetFrameworks
property - you are instructing the build to produce output per each specified target framework.
If you specify TargetFramework
you are instructing the build to produce a single output for that particualar target framework. TargetFramework
gets precedence even if TargetFrameworks
is specified - which might seem as if TargetFrameworks
was ignored.
BC0107
doesn't apply if you explicitly choose to build a single target of multitargeted build:
dotnet build my-multi-target.csproj /p:TargetFramework=net9.0
"'TargetFramework' and 'TargetFrameworks' properties are not respected and should not be specified in projects not using .NET SDK."
'TargetFramework' or 'TargetFrameworks' control the project output targets in modern .NET SDK projects. The older SDK-less projects interprets different properties for similar mechanism (like 'TargetFrameworkVersion') and the 'TargetFramework' or 'TargetFrameworks' are silently ignored.
Make sure the Target Framework is specified appropriately for your project.
"The 'Exec' task should not be used to build projects."
Building projects using the dotnet/msbuild/nuget CLI in the Exec
task is not recommended, as it spawns a separate build process that the MSBuild engine cannot track. Please use the MSBuild task instead.
"A property that is accessed should be declared first."
This check indicates that a property was accessed without being declared (the declaration might have happen later - see BC0202 for such checking). Only accessing in the configured scope (by default it's the project file only) are checked.
There are couple cases which are allowed by the check:
-
Selfreferencing declaration is allowed - e.g.:
<ChainProp>$(ChainProp)</ChainProp>
-
Checking the property for emptyness - e.g.:
<PropertyGroup Condition="'$(PropertyThatMightNotBeDefined)' == ''">
-
Any usage of property in condition. This can be opted out via the configuration
AllowUninitializedPropertiesInConditions
- e.g.:[*.csproj] build_check.BC0201.severity=error build_check.BC0201.AllowUninitializedPropertiesInConditions=false build_check.BC0202.AllowUninitializedPropertiesInConditions=false
BC0201 and BC0202 must have same value for the optional switch - as both operate on top of same data and same filtering.
"A property should be declared before it is first used."
This check indicates that a property was accessed before it was declared. The default scope of this rule is the project file only. The scope captures the read and write operations as well. So this rule reports:
- Uninitialized reads that happened anywhere during the build, while the uninitialized property was later defined within the scope of this check (e.g. project file).
- Uninitialized reads that happened within the scope of check (e.g. project file), while later defined anywhere in the build
If BC0202
and BC0201 are both enabled - then BC0201
reports only the undefined reads that are not reported by this rule (so those that do not have late definitions).
"A property that is not used should not be declared."
This check indicates that a property was defined in the observed scope (by default it's the project file only) and it was then not used anywhere in the build.
This is a runtime check, not a static analysis check - so it can have false positives - for this reasons it's currently not enabled by defaut.
Common cases of false positives:
- Property not used in a particular build might be needed in a build with different conditions or a build of a different target (e.g.
dotnet pack /check
ordotnet build /t:pack /check
accesses some additional properties as compared to ordinarydotnet build /check
). - Property accessing is tracked for each project build request. There might be multiple distinct build requests for a project in a single build. Specific case of this is a call to the MSBuild task or CallTarget task that can request a result from a project build, while passing additional or different global properties and/or calling specific target. This happens often as part of common targets - e.g. for multi-targeted project build parallelization
- Incremental build might skip execution of some targets, that might have been accessing properties of interest.
"Downloads folder is untrusted for projects building."
Placing project files into Downloads folder (or any other folder that cannot be fully trusted including all parent folders up to a root drive) is not recomended, as unintended injection of unrelated MSBuild logic can occur.
Place your projects into trusted locations - including cases when you intend to only open the project in IDE.