Skip to content

Commit b0f9127

Browse files
authored
Fix ASP.NET source generators for non-web projects with FrameworkReference (#50662)
2 parents c5bc828 + bd39736 commit b0f9127

File tree

4 files changed

+88
-13
lines changed

4 files changed

+88
-13
lines changed

src/Cli/dotnet/Commands/Run/CSharpCompilerCommand.Generated.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ private IEnumerable<string> GetCscArguments(
190190
$"/reference:{DotNetRootPath}/packs/Microsoft.NETCore.App.Ref/{RuntimeVersion}/ref/net10.0/System.Xml.XPath.dll",
191191
$"/reference:{DotNetRootPath}/packs/Microsoft.NETCore.App.Ref/{RuntimeVersion}/ref/net10.0/System.Xml.XPath.XDocument.dll",
192192
$"/reference:{DotNetRootPath}/packs/Microsoft.NETCore.App.Ref/{RuntimeVersion}/ref/net10.0/WindowsBase.dll",
193+
"/features:InterceptorsNamespaces=;Microsoft.AspNetCore.Http.Generated;Microsoft.Extensions.Configuration.Binder.SourceGeneration;Microsoft.Extensions.Validation.Generated",
193194
"/debug+",
194195
"/debug:portable",
195196
"/filealign:512",

src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.FrameworkReferenceResolution.targets

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -469,8 +469,25 @@ Copyright (c) .NET Foundation. All rights reserved.
469469
</ItemGroup>
470470
</Target>
471471

472+
<!-- Default "off by default analyzer" settings for trimmed apps. -->
473+
<PropertyGroup Condition="'$(PublishTrimmed)' == 'true' Or '$(PublishAot)' == 'true'">
474+
<!-- Enable the built-in source generators. -->
475+
<EnableRequestDelegateGenerator Condition="'$(EnableRequestDelegateGenerator)' == ''">true</EnableRequestDelegateGenerator>
476+
<EnableConfigurationBindingGenerator Condition="'$(EnableConfigurationBindingGenerator)' == ''">true</EnableConfigurationBindingGenerator>
477+
</PropertyGroup>
478+
479+
<PropertyGroup>
480+
<!-- Set the namespaces emitted by the RequestDelegateGenerator for interception when applicable. -->
481+
<InterceptorsPreviewNamespaces Condition="'$(EnableRequestDelegateGenerator)' == 'true'">$(InterceptorsPreviewNamespaces);Microsoft.AspNetCore.Http.Generated</InterceptorsPreviewNamespaces>
482+
<!-- Set the namespaces emitted by the ConfigurationBindingGenerator for interception when applicable. -->
483+
<InterceptorsPreviewNamespaces Condition="'$(EnableConfigurationBindingGenerator)' == 'true'">$(InterceptorsPreviewNamespaces);Microsoft.Extensions.Configuration.Binder.SourceGeneration</InterceptorsPreviewNamespaces>
484+
<!-- Set the namespaces emitted by the ValidationsGenerator for interception when applicable (.NET 10 and above). -->
485+
<InterceptorsPreviewNamespaces Condition="'$(_TargetFrameworkVersionWithoutV)' != '' and $([MSBuild]::VersionGreaterThanOrEquals('$(_TargetFrameworkVersionWithoutV)', '10.0'))">$(InterceptorsPreviewNamespaces);Microsoft.Extensions.Validation.Generated</InterceptorsPreviewNamespaces>
486+
</PropertyGroup>
487+
472488
<Target Name="ResolveOffByDefaultAnalyzers" AfterTargets="ResolveTargetingPackAssets"
473489
Condition="'@(FrameworkReference)' != ''">
490+
474491
<ItemGroup>
475492
<OffByDefaultAnalyzer Include="Microsoft.AspNetCore.Http.RequestDelegateGenerator.dll"
476493
IsEnabled="$(EnableRequestDelegateGenerator)"/>

src/WebSdk/ProjectSystem/Targets/Microsoft.NET.Sdk.Web.ProjectSystem.targets

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -54,25 +54,12 @@ Copyright (c) .NET Foundation. All rights reserved.
5454

5555
<!-- Default settings for trimmed apps. -->
5656
<PropertyGroup Condition="'$(PublishTrimmed)' == 'true' Or '$(PublishAot)' == 'true'">
57-
<!-- Enable the built-in source generators. -->
58-
<EnableRequestDelegateGenerator Condition="'$(EnableRequestDelegateGenerator)' == ''">true</EnableRequestDelegateGenerator>
59-
<EnableConfigurationBindingGenerator Condition="'$(EnableConfigurationBindingGenerator)' == ''">true</EnableConfigurationBindingGenerator>
60-
6157
<!-- Default feature switch values for trimmed apps. -->
6258
<SignalRCustomAwaitableSupport Condition="'$(SignalRCustomAwaitableSupport)' == ''">false</SignalRCustomAwaitableSupport>
6359
<MvcEnhancedModelMetadataSupport Condition="'$(MvcEnhancedModelMetadataSupport)' == ''">false</MvcEnhancedModelMetadataSupport>
6460
<BlazorDisableThrowNavigationException Condition="'$(BlazorDisableThrowNavigationException)' == ''">false</BlazorDisableThrowNavigationException>
6561
</PropertyGroup>
6662

67-
<PropertyGroup>
68-
<!-- Set the namespaces emitted by the RequestDelegateGenerator for interception when applicable. -->
69-
<InterceptorsPreviewNamespaces Condition="'$(EnableRequestDelegateGenerator)' == 'true'">$(InterceptorsPreviewNamespaces);Microsoft.AspNetCore.Http.Generated</InterceptorsPreviewNamespaces>
70-
<!-- Set the namespaces emitted by the ConfigurationBindingGenerator for interception when applicable. -->
71-
<InterceptorsPreviewNamespaces Condition="'$(EnableConfigurationBindingGenerator)' == 'true'">$(InterceptorsPreviewNamespaces);Microsoft.Extensions.Configuration.Binder.SourceGeneration</InterceptorsPreviewNamespaces>
72-
<!-- Set the namespaces emitted by the ValidationsGenerator for interception when applicable (.NET 10 and above). -->
73-
<InterceptorsPreviewNamespaces Condition="'$(_TargetFrameworkVersionWithoutV)' != '' and $([MSBuild]::VersionGreaterThanOrEquals('$(_TargetFrameworkVersionWithoutV)', '10.0'))">$(InterceptorsPreviewNamespaces);Microsoft.Extensions.Validation.Generated</InterceptorsPreviewNamespaces>
74-
</PropertyGroup>
75-
7663
<!--
7764
Newer versions of Visual Studio ship the designtime related properties in a targets file and all future design time only elements should be added there. If that file does not
7865
exist, it falls back to the default set of values defined here.

test/Microsoft.NET.Build.Tests/GivenThatWeWantToUseAnalyzers.cs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,76 @@ private void VerifyInterceptorsFeatureProperties(TestAsset asset, bool? expectEn
152152
Assert.Equal(expectEnabled ?? false, expectedNamespaces.All(expectedNamespace => namespaces.Contains(expectedNamespace)));
153153
}
154154

155+
[Fact]
156+
public void It_enables_aspnet_generators_for_non_web_projects_with_framework_reference()
157+
{
158+
var testProject = new TestProject()
159+
{
160+
Name = "NonWebAppWithAspNet",
161+
TargetFrameworks = ToolsetInfo.CurrentTargetFramework,
162+
IsSdkProject = true,
163+
IsExe = true,
164+
};
165+
166+
testProject.AdditionalProperties["ImplicitUsings"] = "Enable";
167+
168+
testProject.ProjectChanges.Add(project =>
169+
{
170+
var ns = project.Root.Name.Namespace;
171+
172+
// Add FrameworkReference to ASP.NET Core (this is key to reproducing the issue)
173+
project.Root.Add(new XElement(ns + "ItemGroup",
174+
new XElement(ns + "FrameworkReference", new XAttribute("Include", "Microsoft.AspNetCore.App"))));
175+
176+
// Enable configuration binding generator explicitly (like the repro in the issue)
177+
project.Root.Add(new XElement(ns + "PropertyGroup",
178+
new XElement(ns + "EnableConfigurationBindingGenerator", "true")));
179+
});
180+
181+
testProject.SourceFiles["Program.cs"] = """
182+
using Microsoft.Extensions.Configuration;
183+
184+
var c = new ConfigurationBuilder()
185+
.AddInMemoryCollection(new Dictionary<string,string?>()
186+
{
187+
["Value"] = "42",
188+
})
189+
.Build();
190+
C value = new();
191+
c.Bind(value);
192+
193+
class C { public int Value { get; set; } }
194+
""";
195+
196+
// Create a simple non-web project with ASP.NET FrameworkReference
197+
var asset = _testAssetsManager
198+
.CreateTestProject(testProject);
199+
200+
new BuildCommand(asset)
201+
.Execute()
202+
.Should().Pass();
203+
204+
// Get the actual values to see what's happening
205+
var command = new GetValuesCommand(
206+
Log,
207+
Path.Combine(asset.Path, "NonWebAppWithAspNet"),
208+
ToolsetInfo.CurrentTargetFramework,
209+
"InterceptorsPreviewNamespaces",
210+
GetValuesCommand.ValueType.Property);
211+
212+
command
213+
.WithWorkingDirectory(asset.Path)
214+
.Execute()
215+
.Should().Pass();
216+
217+
var namespaces = command.GetValues();
218+
219+
// This should work correctly - the non-web project should get the InterceptorsPreviewNamespaces
220+
// because the logic was moved from Web SDK to FrameworkReferenceResolution targets
221+
Assert.True(namespaces.Contains("Microsoft.Extensions.Configuration.Binder.SourceGeneration"),
222+
$"Expected InterceptorsPreviewNamespaces to contain 'Microsoft.Extensions.Configuration.Binder.SourceGeneration' but got: [{string.Join(", ", namespaces)}]");
223+
}
224+
155225
[Theory]
156226
[InlineData("C#", "AppWithLibrary")]
157227
[InlineData("VB", "AppWithLibraryVB")]

0 commit comments

Comments
 (0)