Purview.DotNetProjectSdk
1.0.0-prerelease.5
See the version list below for details.
<Sdk Name="Purview.DotNetProjectSdk" Version="1.0.0-prerelease.5" />
#:sdk Purview.DotNetProjectSdk@1.0.0-prerelease.5
Purview.DotNetProjectSdk
A reusable MSBuild SDK NuGet package that delivers standardised .NET project defaults, code-style enforcement, test-framework wiring, and Central Package Management integration. Install it once per repo — every project beneath the repo root inherits everything automatically.
What's included
| Feature | Detail |
|---|---|
| Project type detection | IsCSharpProject, IsTestProject, IsSharedTestingProject, IsContainerProject, IsWebSdkProject, IsAspireHostProject, … |
| C# defaults | net10.0 TFM (overridable), LangVersion=preview, Nullable=enable, ImplicitUsings=enable, deterministic builds |
| Code style | .editorconfig baked into the package, applied via EditorConfigFilePath, and auto-bootstrapped to repo root if missing; EnforceCodeStyleInBuild=true |
| Repo bootstrap | Missing repo-root .editorconfig and global.json are auto-copied/created by default (disable via DisableAutoCopySdkFiles=true) |
| CI detection | ContinuousIntegrationBuild set automatically when CI, GITHUB_ACTIONS, or TF_BUILD env vars are present |
| SourceLink | Microsoft.SourceLink.GitHub added to all packable projects (configurable via SourceLinkPackageName) |
| Purview Telemetry | Purview.Telemetry.SourceGenerator + Microsoft.Extensions.Telemetry.Abstractions added by default (opt-out) |
| Assembly info | Auto-generated static class AssemblyInfo with RootNamespace, Version, Company, etc., plus an embedded Microsoft.CodeAnalysis.EmbeddedAttribute (can be excluded via PURVIEW_SDK_EXCLUDE_EMBEDDED). |
| InternalsVisibleTo | Generated for all defined TestType variants automatically |
| Namespace management | NamespacePrefix.ProjectName pattern with suffix stripping (.Core, .Shared, .EF, …) |
| Test framework | TUnit by default; switch to XUnit v3 with one property |
| Testing extras | NSubstitute, Bogus, Microsoft.Testing.Platform.MSBuild wiring and coverage defaults |
| Version detection | Reads version from package.json and applies it to Version and PackageVersion automatically; falls back to 0.0.1 |
| CPM | ManagePackageVersionsCentrally=true — versions live in your Directory.Packages.props |
Quick start
1. Add the SDK to global.json
{
"test": {
"runner": "Microsoft.Testing.Platform"
},
"msbuild-sdks": {
"Purview.DotNetProjectSdk": "1.0.0"
}
}
2. Create Directory.Build.props at repo root
<Project>
<PropertyGroup>
<NamespacePrefix>YourCompany</NamespacePrefix>
</PropertyGroup>
<Import Sdk="Purview.DotNetProjectSdk" Project="Sdk.props" />
</Project>
3. Create Directory.Build.targets at repo root
<Project>
<Import Sdk="Purview.DotNetProjectSdk" Project="Sdk.targets" />
</Project>
4. Copy Directory.Packages.props to repo root
Copy templates/Directory.Packages.props from this package to your repo root. All package versions default to * (latest at restore). Pin any package by replacing * with a specific version.
Note:
ManagePackageVersionsCentrally=trueis set by the SDK. You must have aDirectory.Packages.propsat your repo root for CPM to work, even if it only contains the packages the SDK adds automatically.
Template files
The templates/ folder contains ready-to-copy starter files for new repos:
| File | Purpose |
|---|---|
Directory.Build.props |
Bootstrapper — copy to repo root and set NamespacePrefix |
Directory.Build.targets |
Bootstrapper — copy to repo root |
Directory.Packages.props |
All default package versions with * floating to latest |
global.json |
msbuild-sdks entry + Microsoft.Testing.Platform test runner |
.gitignore |
ASP.NET Core + VS + Rider + Node combined gitignore |
.gitattributes |
Line-ending normalisation for .cs, .json, .yml, etc. |
.config/dotnet-tools.json |
CSharpier tool manifest |
Configuration reference
Set any of these properties before the <Import> in your Directory.Build.props:
Version detection
| Property | Default | Description |
|---|---|---|
UsePackageJsonVersion |
true |
Set to false to disable reading Version/PackageVersion from package.json. |
RootPackageJson |
(auto-discovered) | Explicit path to a package.json. Relative paths are resolved from the project directory. |
When UsePackageJsonVersion=true (the default) the SDK:
- Explicit path — if
RootPackageJsonis set, reads that file directly. - Auto-discovery — otherwise, walks up from the project directory looking for a
.gitmarker to locate the repo root, then readspackage.jsonfrom there.
The extracted version field is applied to both Version and PackageVersion. A build error is raised if the file can't be found or contains no version field.
Important — set before the import: Both
UsePackageJsonVersionandRootPackageJsonmust be set before the<Import Sdk="Purview.DotNetProjectSdk" Project="Sdk.props" />line in yourDirectory.Build.props. The version logic runs during that import and cannot see properties set afterwards (e.g. in individual.csprojfiles).<Project> <PropertyGroup> <NamespacePrefix>Acme</NamespacePrefix> <RootPackageJson>$(MSBuildThisFileDirectory)package.json</RootPackageJson> </PropertyGroup> <Import Sdk="Purview.DotNetProjectSdk" Project="Sdk.props" /> </Project>
General
| Property | Default | Description |
|---|---|---|
NamespacePrefix |
(required) | Root namespace prefix, e.g. Acme. Results in Acme.MyProject. |
DisableNamespacePrefixCheck |
false |
Set to true to suppress the build error for missing NamespacePrefix. |
TargetFramework |
net10.0 |
Override the default TFM per-project or globally. |
SourceLinkPackageName |
Microsoft.SourceLink.GitHub |
SourceLink provider. Set to Microsoft.SourceLink.AzureDevOps.Git for ADO repos. |
Telemetry
| Property | Default | Description |
|---|---|---|
ExcludePurviewTelemetry |
false |
Set to true to remove Purview.Telemetry.SourceGenerator from all projects. |
ExcludeMSTelemetryExtension |
false |
Set to true to remove Microsoft.Extensions.Telemetry.Abstractions. |
Testing
| Property | Default | Description |
|---|---|---|
ProjectSdkTestFramework |
TUnit |
Testing framework. Set to XUnit to switch to xunit v3. |
DisableAutoInternalsVisibleTo |
false |
Set to true to disable automatic InternalsVisibleTo generation for test types and shared testing projects. |
Compiler-visible SDK properties
The SDK now exports its properties via CompilerVisibleProperty, so analyzers and source generators can read them through build_property.<PropertyName>.
| Property | Description |
|---|---|
UsePackageJsonVersion |
Whether version detection from package.json is active. |
RootPackageJson |
Resolved path to the package.json used for version detection. |
RepoRoot |
Repo root directory found via .git auto-discovery. |
Version |
Package/assembly version, sourced from package.json when detection is enabled. |
PackageVersion |
NuGet package version, sourced from package.json when detection is enabled. |
NamespacePrefix |
Required namespace prefix used to derive RootNamespace. |
DisableNamespacePrefixCheck |
Disables the build error for missing NamespacePrefix. |
ProjectSdkTestFramework |
Selected test framework (TUnit by default, XUnit opt-in). |
SourceLinkPackageName |
SourceLink package ID added by the SDK. |
ExcludePurviewTelemetry |
Opt-out for Purview.Telemetry.SourceGenerator. |
ExcludeMSTelemetryExtension |
Opt-out for Microsoft.Extensions.Telemetry.Abstractions. |
DisableGenerateAssemblyInfoClass |
Disables generated AssemblyInfo helper source. |
DisableAutoInternalsVisibleTo |
Disables automatic InternalsVisibleTo generation. |
AutoIncludeUsings |
Controls SDK-added global usings. |
IsCSharpProject |
True when the project is a .csproj. |
IsTestProject |
True when project name ends with a supported test suffix. |
IsSharedTestingProject |
True for known shared testing helper project names. |
TestingType |
Detected test category suffix from project name. |
TargetProjectName |
Inferred target project name for test projects. |
IsContainerProject |
True when Dockerfile markers indicate container defaults. |
IsSdkProject |
True when an SDK value is detected from project/import declaration. |
SdkProjectName |
Detected SDK name (e.g. Microsoft.NET.Sdk.Web). |
IsWebProject |
Marker used in SDK web-project behavior. |
IsWebSdkProject |
True when SdkProjectName is Microsoft.NET.Sdk.Web. |
IsWorkerSdkProject |
True when SdkProjectName is Microsoft.NET.Sdk.Worker. |
IsAspireHostProject |
True when SDK starts with Aspire.Sdk.Host. |
EditorConfigFilePath |
Path to the SDK-provided .editorconfig that is injected into @(EditorConfigFiles). |
RepositoryEditorConfigFilePath |
Destination path for bootstrapping a physical repo-level .editorconfig (defaults to git repo root; falls back to Directory.Build.props directory). |
BootstrapEditorConfigToRepoRoot |
When true (default), copies the SDK .editorconfig to RepositoryEditorConfigFilePath if missing. |
RepositoryGlobalJsonFilePath |
Destination path for bootstrapping a physical repo-level global.json (defaults to git repo root; falls back to Directory.Build.props directory). |
BootstrapGlobalJsonToRepoRoot |
When true (default), creates global.json at RepositoryGlobalJsonFilePath if missing. |
PurviewDotNetProjectSdkVersionForGlobalJson |
Version used for msbuild-sdks.Purview.DotNetProjectSdk when bootstrapping global.json (auto-detected from SDK package path, fallback 1.0.0). |
DisableAutoCopySdkFiles |
When true, disables SDK auto-copy/bootstrap for repo files (.editorconfig, global.json). |
CurrentYear |
Current year used in generated assembly metadata. |
AutoGeneratedAssemblyInfoFile |
Relative path to generated AssemblyInfo source file. |
Example: switch a repo to XUnit
<Project>
<PropertyGroup>
<NamespacePrefix>Acme</NamespacePrefix>
<ProjectSdkTestFramework>XUnit</ProjectSdkTestFramework>
</PropertyGroup>
<Import Sdk="Purview.DotNetProjectSdk" Project="Sdk.props" />
</Project>
Test project naming conventions
Test projects are automatically detected by their suffix. Supported patterns:
MyProject.UnitTests → IsTestProject=true, TestingType=Unit
MyProject.IntegrationTests→ IsTestProject=true, TestingType=Integration
MyProject.E2ETests → IsTestProject=true, TestingType=E2E
Any suffix from the full list is recognised: Unit, Integration, E2E, EndToEnd, Acceptance, Functional, Performance, Load, Smoke, Stress, Regression, Security, Chaos, Scenario, System, Threat, BlackBox, WhiteBox, Accessibility, Interactive, Environment.
Shared testing projects
Projects named SharedTestingFramework, SharedTestingInfrastructure, SharedTestingInfra, SharedTestingUtilities, SharedTestingLibrary, SharedTestingLib, or SharedTestingHelpers are treated as shared testing helpers — they get test package references but not the test runner or coverage settings.
InternalsVisibleTo
The SDK automatically generates [assembly: InternalsVisibleTo("MyProject.UnitTests")] (and all other TestType variants) for every non-test project. This allows test projects to access internal members. No manual attributes required.
Additionally, all SharedTesting projects (like SharedTestingFramework, SharedTestingInfrastructure, etc.) are also granted access to internals, so shared testing infrastructure has full visibility into the projects being tested.
Disabling automatic InternalsVisibleTo
To disable automatic InternalsVisibleTo generation, set DisableAutoInternalsVisibleTo=true in your project or Directory.Build.props:
<PropertyGroup>
<DisableAutoInternalsVisibleTo>true</DisableAutoInternalsVisibleTo>
</PropertyGroup>
EmbeddedAttribute generation
When GenerateAssemblyInfoClassTarget writes the SDK-generated AssemblyInfo source, it also emits:
namespace Microsoft.CodeAnalysis
{
sealed partial class EmbeddedAttribute : System.Attribute { }
}
This block is guarded by:
#if !PURVIEW_SDK_EXCLUDE_EMBEDDED
AssemblyInfo is emitted with [Microsoft.CodeAnalysis.Embedded], so the project must have a matching Microsoft.CodeAnalysis.EmbeddedAttribute type available at compile time. The SDK emits that attribute to satisfy the reference and to keep generated metadata/source-generator-facing symbols marked as embedded.
Define PURVIEW_SDK_EXCLUDE_EMBEDDED only when your build already provides Microsoft.CodeAnalysis.EmbeddedAttribute from another source; otherwise compilation will fail because the attribute used by generated AssemblyInfo cannot be resolved.
Namespace stripping
Certain suffixes are automatically stripped from RootNamespace to avoid awkward namespace names like Acme.MyProject.Core.Something:
Stripped suffixes: Core, EF, Shared, ClientShared, ServiceDefaults, and all shared testing project names.
Central Package Management
The SDK sets ManagePackageVersionsCentrally=true. The templates/Directory.Packages.props file contains PackageVersion entries for all packages the SDK auto-adds — all set to Version="*" (floating to latest).
To pin a package:
<PackageVersion Include="TUnit" Version="1.45.29" />
To add project-specific packages, just append PackageVersion entries to your Directory.Packages.props.
Building the SDK
dotnet build src/DotNetProjectSdk.slnx -c Release
dotnet test src/DotNetProjectSdk.slnx -c Release
dotnet pack src/src/DotNetProjectSdk/DotNetProjectSdk.csproj -o ./artifacts
License
MIT
Learn more about Target Frameworks and .NET Standard.
-
.NETStandard 2.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.0-prerelease.15 | 53 | 6/22/2026 |
| 1.0.0-prerelease.14 | 50 | 6/22/2026 |
| 1.0.0-prerelease.13 | 53 | 6/22/2026 |
| 1.0.0-prerelease.12 | 55 | 6/22/2026 |
| 1.0.0-prerelease.11 | 51 | 6/20/2026 |
| 1.0.0-prerelease.10 | 51 | 6/20/2026 |
| 1.0.0-prerelease.9 | 53 | 6/20/2026 |
| 1.0.0-prerelease.8 | 54 | 6/20/2026 |
| 1.0.0-prerelease.7 | 50 | 6/20/2026 |
| 1.0.0-prerelease.6 | 52 | 6/20/2026 |
| 1.0.0-prerelease.5 | 111 | 6/9/2026 |
| 1.0.0-prerelease.4 | 58 | 6/6/2026 |
| 1.0.0-prerelease.3 | 56 | 6/6/2026 |
| 1.0.0-prerelease.2 | 47 | 6/5/2026 |