This page documents the detection mechanics behind the policy described in Engineering Principles.
During Sdk.props evaluation the SDK classifies every .csproj by reading the project filename, the
Sdk attribute, and on-disk markers. The resulting flags drive the defaults described throughout this
wiki.
| Flag | Condition |
|---|---|
IsCSharpProject |
Project file extension is .csproj. |
IsTestProject |
Project name matches `^.*.([\w |
IsSharedTestingProject |
Project name is one of SharedTestingFramework, SharedTestingInfrastructure, SharedTestingInfra, SharedTestingUtilities, SharedTestingUtils, SharedTestingLibrary, SharedTestingLib, SharedTestingHelpers. |
IsSharedProject |
Project name is one of Shared, SharedFramework, SharedInfrastructure, SharedInfra, SharedUtilities, SharedUtils, SharedLibrary, SharedLib, SharedHelpers. |
IsContainerProject |
A Dockerfile, dockerfile, or Dockerfile.dev exists in the project directory. |
IsSdkProject |
An Sdk value is parsed from the <Project>/<Import> element. |
IsWebSdkProject |
SdkProjectName is Microsoft.NET.Sdk.Web. |
IsWorkerSdkProject |
SdkProjectName is Microsoft.NET.Sdk.Worker. |
IsAspireHostProject |
SdkProjectName starts with Aspire.Sdk.Host or Aspire.AppHost.Sdk. |
IsCLIProject |
Project name ends with CLI, Console, CommandLine, QuickStart, or QuickStarts. |
IsBlazorWebAssemblyProject |
SdkProjectName is Microsoft.NET.Sdk.BlazorWebAssembly. |
IsRazorClassLibraryProject |
SdkProjectName is Microsoft.NET.Sdk.Razor. |
IsBffProject |
A web SDK project whose name ends with Bff (case-sensitive), or that sets IsBffProject=true. IsBffProject=false opts out. |
IsBlazorHostProject |
A web SDK project that references an IsBlazorWebAssemblyProject project - at evaluation for the <Name>/<Name>.Client pairing, during the build (ResolvePurviewBlazorHostProject) otherwise. Never implies IsBffProject. |
IsRoslynComponent |
<IsRoslynComponent>true</IsRoslynComponent> is declared in the project file. |
IsPackable |
<IsPackable>true</IsPackable> is declared in the project file. |
IsWebProject |
Marker used in SDK web-project behaviour. |
TestingType is the detected test category suffix from the project name (for example Unit,
Integration, E2E); TargetProjectName is the inferred non-test project name that a test project
targets. The detected TestingType also becomes the baseline test category, while additional categories
remain available to the test suite.
Detection is a pattern, not a lookup against the set below. A project named MyProject.GoldenTests
is detected, and gets TestingType=Golden and Category=Golden, even though Golden appears nowhere in
the SDK. The pattern requires the dot, so a project named plainly UnitTests is not detected as a
test project at all — it gets no runner, no coverage and no category.
The TestType item group below governs InternalsVisibleTo generation instead: a
non-test project grants access to {AssemblyName}.{TestType}Tests for each name on it. A suffix outside
the set still builds, still runs and still gets its category — it just cannot reach the target project's
internal members.
The SDK ships the following full TestType set, in addition to the standard Unit and
Integration values:
Acceptance, Accessibility, Approval, Architecture, Benchmark, BlackBox, Capacity,
Chaos, Compatibility, Compliance, Component, Concurrency, Configuration, Contract,
Deployment, E2E, EndToEnd, Endurance, Environment, Failover, Functional, Fuzz,
Globalization, GrayBox, GreyBox, Integration, Interactive, Interoperability, Load,
Localization, Migration, Mutation, Penetration, Performance, Property, Recovery,
Regression, Resilience, Sanity, Scenario, Security, Smoke, Snapshot, Soak, Spike,
Stress, System, Threat, Unit, Upgrade, Usability, Visual, and WhiteBox.
OutputType=Exewhen the testing framework is notNone.- A test-context rule set (
PurviewTestContextNoWarn): the production API-surface rules (CA1002,CA1012,CA1034,CA1047,CA1050,CA1051,CA1062,CA1064,CA1515,CA1707) are exempt, while the strict style contract (IDE0040, field naming, formatting,IDE1006naming rules) still applies.DisablePurviewTestContextRuleSet=trueenforces the production rules instead. CollectCoverage=truewith coverage exclusions for framework and mocking packages.IsPackable=false,IsPublishable=false,MaxCpuCount=0.- Disabled native instrumentation by default.
- An
[assembly: ExcludeFromCodeCoverage]attribute. - Automatic
ProjectReferenceto the target project (resolved as../<TargetProjectName>/, siblingsrc/paths, and the shared testing project alongside). - A
[Category: <TestingType>]assembly attribute (TUnit) or[Trait("Category", ...)](Xunit).
- Test package references, but not the test runner or coverage settings.
- A
[Skip]attribute (TUnit) so the shared assembly is never executed directly. TUnit.Coreinstead of the fullTUnitpackage.OutputType=LibrarywithIsTestProject/IsTestingPlatformApplicationcleared, reasserted after the package props (which otherwise flip the project into an executable test host). The fixtures are consumed by the test assemblies, so staying a library avoidsCA1515(which only targets executables). SetPurviewSharedTestingOutputType=Exebefore the SDK import to keep the package-driven test-host shape.
- Automatically referenced by sibling non-test projects via wildcard
(
../Shared*/Shared*.csproj); test projects automatically reference../SharedTesting*/SharedTesting*.csproj.
InvariantGlobalization=true,PublishAot=true,DockerDefaultTargetOS=Linux,DockerfileContext=..\..\.- Adds
Microsoft.VisualStudio.Azure.Containers.Tools.Targets.
- Non-API web apps get
InterceptorsNamespacesextended withMicrosoft.AspNetCore.OpenApi.Generatedfor OpenAPI interceptors.
OutputType=Exe,appsettings*.jsoncopied to the output directory.CA1515suppressed (nested settings classes on internal commands).
OutputType=Exe(when not a test/shared-testing project),CA1515suppressed.
IsPackable=falseunless the project sets it, no container defaults even with aDockerfile, and no automatic../Shared*reference.DisablePurviewBlazorWebAssemblyDefaults=true(before the SDK import) restores the generic defaults.PRBLZ0001for eachProjectReferencethat does not setPurviewBrowserSafe.- Globalisation, trimming and the Blazor runtime settings are left to the Blazor SDK.
- A host named
<Name>gets an automatic reference to its<Name>.Clientclient unless it declares one.PurviewAutoBlazorClientReference=falseopts out.
- No packages added. No OpenAPI interceptor namespace unless the BFF references
Microsoft.AspNetCore.OpenApior setsPurviewBffExposesApi=true. PDS0008/PDS0009on the authentication cookie (see Analyzers).
IsAotCompatible=true,<SupportedPlatform Include="browser" />, and the trim, single-file, AOT andCA1416ids inWarningsAsErrors- each only where the project set nothing.PurviewBrowserSafeWarningsAsErrors=falsekeeps them as warnings.- The same
PRBLZ0001reference check a client runs.
The README's Blazor WebAssembly and BFF section has the failure each behaviour prevents.
- Default
netstandard2.0target,LangVersion=latest,Nullable=enable,TreatWarningsAsErrors=true,EnforceExtendedAnalyzerRules=true,Deterministic=true. - Compiler-generated output under the intermediate directory, no dependency file.
- No symbol package by default; the PDB ships beside the analyzer in the package.
- SourceLink with
EmbedUntrackedSources=true, telemetry excluded. - See Packaging for how the analyzer assets are packed.
GenerateDocumentationFile,IncludeSource,IncludeSymbols(.snupkg),PublishRepositoryUrl,EmbedUntrackedSources,DebugType=portabledefaults.- See Packaging.
The detection flags (plus many SDK properties) are exposed to Roslyn analyzers and source generators
via CompilerVisibleProperty, readable as build_property.<PropertyName>. The full list is in the
Configuration Reference.