diff --git a/Directory.Build.BeforeCommonTargets.targets b/Directory.Build.BeforeCommonTargets.targets
index 8339d8e3ca0c..6395f6c74dc6 100644
--- a/Directory.Build.BeforeCommonTargets.targets
+++ b/Directory.Build.BeforeCommonTargets.targets
@@ -15,6 +15,7 @@
@@ -30,6 +30,9 @@
$(MSBuildProjectName.EndsWith('.Test')) OR
$(MSBuildProjectName.EndsWith('.FunctionalTest')) ) ">true
false
+ true
+ true
+ true
true
false
+ 99.9
+
+ true
+ full
+ true
+ true
+
+ true
+
+
diff --git a/eng/testing/linker/SupportFiles/Directory.Build.targets b/eng/testing/linker/SupportFiles/Directory.Build.targets
new file mode 100644
index 000000000000..a2a18b071459
--- /dev/null
+++ b/eng/testing/linker/SupportFiles/Directory.Build.targets
@@ -0,0 +1,25 @@
+
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/eng/testing/linker/project.csproj.template b/eng/testing/linker/project.csproj.template
new file mode 100644
index 000000000000..59333742ae1c
--- /dev/null
+++ b/eng/testing/linker/project.csproj.template
@@ -0,0 +1,22 @@
+
+
+
+ {TargetFramework}
+ Exe
+ {RuntimeIdentifier}
+ {PublishAot}
+ {MicrosoftNETCoreAppRuntimeVersion}
+ {RepoRoot}
+ <_ExtraTrimmerArgs>{ExtraTrimmerArgs} $(_ExtraTrimmerArgs)
+ {AdditionalProperties}
+
+
+
+ {RuntimeHostConfigurationOptions}
+
+
+
+ {AdditionalProjectReferences}
+
+
+
diff --git a/eng/testing/linker/trimmingTests.props b/eng/testing/linker/trimmingTests.props
new file mode 100644
index 000000000000..4158daec9957
--- /dev/null
+++ b/eng/testing/linker/trimmingTests.props
@@ -0,0 +1,20 @@
+
+
+ $([MSBuild]::NormalizeDirectory('$(ArtifactsBinDir)', 'trimmingTests'))
+ $([MSBuild]::NormalizeDirectory('$(TrimmingTestDir)', 'projects'))
+ $(MSBuildThisFileDirectory)project.csproj.template
+
+
+ false
+ false
+
+
+
+
+ $(DefaultNetCoreTargetFramework)
+
+
+ true
+
+
+
diff --git a/eng/testing/linker/trimmingTests.targets b/eng/testing/linker/trimmingTests.targets
new file mode 100644
index 000000000000..5f5fcb99736a
--- /dev/null
+++ b/eng/testing/linker/trimmingTests.targets
@@ -0,0 +1,132 @@
+
+
+
+
+
+
+
+ $(TrimmingTestDir)
+
+
+
+
+
+
+
+
+
+
+
+ $([MSBuild]::NormalizeDirectory('$(TrimmingTestProjectsDir)', '$(MSBuildProjectName)', '%(Filename)', '$(PackageRID)'))
+ $(TargetRuntimeIdentifier)
+ $(DefaultNetCoreTargetFramework)
+ $(DefaultNetCoreTargetFramework)-%(TestConsoleAppSourceFiles.TargetOS)
+
+
+
+ %(ProjectDir)project.csproj
+ $([MSBuild]::NormalizePath('%(ProjectDir)', 'bin', '$(Configuration)', '%(TargetFramework)', '%(TestRuntimeIdentifier)', 'publish', 'project'))
+ $([MSBuild]::NormalizeDirectory('%(ProjectDir)', 'bin', '$(Configuration)', '%(TargetFramework)', '%(TestRuntimeIdentifier)', 'publish'))
+
+
+
+
+
+ %(FullPath)
+
+
+
+
+
+
+
+ <_projectDir>%(TestConsoleApps.ProjectDir)\
+ <_projectFile>%(TestConsoleApps.ProjectFile)
+ <_projectSourceFile>%(TestConsoleApps.ProjectCompileItems)
+
+
+
+ <_additionalProjectReferenceTemp Include="$(AdditionalProjectReferences)" />
+ <_additionalProjectReference Include="<ProjectReference Include="$(LibrariesProjectRoot)%(_additionalProjectReferenceTemp.Identity)\src\%(_additionalProjectReferenceTemp.Identity).csproj" SkipUseReferenceAssembly="true" />" />
+
+
+
+ <_additionalProjectReferencesString>@(_additionalProjectReference, '%0a')
+
+
+
+ <_additionalProjectSourceFiles Include="%(TestConsoleApps.AdditionalSourceFiles)" />
+
+
+
+ <_switchesAsItems Include="%(TestConsoleApps.DisabledFeatureSwitches)" Value="false" />
+ <_switchesAsItems Include="%(TestConsoleApps.EnabledFeatureSwitches)" Value="true" />
+
+ <_propertiesAsItems Include="%(TestConsoleApps.DisabledProperties)" Value="false" />
+ <_propertiesAsItems Include="%(TestConsoleApps.EnabledProperties)" Value="true" />
+
+
+
+ <_runtimeHostConfigurationOptionsString>@(_switchesAsItems->'<RuntimeHostConfigurationOption Include="%(Identity)" Value="%(Value)" Trim="true" />', '%0a ')
+ <_additionalPropertiesString>@(_propertiesAsItems->'<%(Identity)>%(Value)</%(Identity)>', '%0a ')
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/DefaultBuilder/test/Microsoft.AspNetCore.NativeAotTests/Microsoft.AspNetCore.NativeAotTests.proj b/src/DefaultBuilder/test/Microsoft.AspNetCore.NativeAotTests/Microsoft.AspNetCore.NativeAotTests.proj
new file mode 100644
index 000000000000..b17fb2b6f5c3
--- /dev/null
+++ b/src/DefaultBuilder/test/Microsoft.AspNetCore.NativeAotTests/Microsoft.AspNetCore.NativeAotTests.proj
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/DefaultBuilder/test/Microsoft.AspNetCore.NativeAotTests/UseStartupThrowsForStructContainersTest.cs b/src/DefaultBuilder/test/Microsoft.AspNetCore.NativeAotTests/UseStartupThrowsForStructContainersTest.cs
new file mode 100644
index 000000000000..ef5951c9cbb3
--- /dev/null
+++ b/src/DefaultBuilder/test/Microsoft.AspNetCore.NativeAotTests/UseStartupThrowsForStructContainersTest.cs
@@ -0,0 +1,139 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+using System;
+
+int classTestResult = RunClassTest();
+if (classTestResult != 100)
+{
+ return classTestResult;
+}
+
+return RunStructTest();
+
+static int RunClassTest()
+{
+ var builder = Host.CreateDefaultBuilder();
+ builder.UseServiceProviderFactory(new MyContainerClassFactory());
+
+ builder.ConfigureWebHost(webBuilder =>
+ {
+ webBuilder.UseStartup(typeof(MyStartupWithClass));
+ });
+
+ builder.Build();
+
+ if (!MyStartupWithClass.ConfigureServicesCalled)
+ {
+ return -1;
+ }
+ if (!MyStartupWithClass.ConfigureContainerCalled)
+ {
+ return -2;
+ }
+
+ return 100;
+}
+
+static int RunStructTest()
+{
+ var builder = Host.CreateDefaultBuilder();
+ builder.UseServiceProviderFactory(new MyContainerStructFactory());
+
+ builder.ConfigureWebHost(webBuilder =>
+ {
+ webBuilder.UseStartup(typeof(MyStartupWithStruct));
+ });
+
+ try
+ {
+ builder.Build();
+ return -3;
+ }
+ catch (InvalidOperationException e)
+ {
+ if (!e.Message.StartsWith("A ValueType TContainerBuilder isn't supported with AOT", StringComparison.Ordinal))
+ {
+ return -4;
+ }
+ }
+
+ if (!MyStartupWithStruct.ConfigureServicesCalled)
+ {
+ return -5;
+ }
+
+ // ConfigureContainer should not have been called, since the exception should have been raised
+ if (MyStartupWithStruct.ConfigureContainerCalled)
+ {
+ return -6;
+ }
+
+ return 100;
+}
+
+public class MyStartupWithClass
+{
+ public static bool ConfigureServicesCalled;
+ public static bool ConfigureContainerCalled;
+
+ public void ConfigureServices(IServiceCollection _) => ConfigureServicesCalled = true;
+ public void ConfigureContainer(MyContainerClass _) => ConfigureContainerCalled = true;
+ public void Configure(IApplicationBuilder _) { }
+}
+
+public class MyContainerClassFactory : IServiceProviderFactory
+{
+ public MyContainerClass CreateBuilder(IServiceCollection services) => new MyContainerClass(services);
+
+ public IServiceProvider CreateServiceProvider(MyContainerClass containerBuilder)
+ {
+ containerBuilder.Build();
+ return containerBuilder;
+ }
+}
+
+public class MyContainerClass : IServiceProvider
+{
+ private IServiceProvider _inner;
+ private IServiceCollection _services;
+
+ public MyContainerClass(IServiceCollection services) => _services = services;
+ public void Build() => _inner = _services.BuildServiceProvider();
+ public object GetService(Type serviceType) => _inner.GetService(serviceType);
+}
+
+public class MyStartupWithStruct
+{
+ public static bool ConfigureServicesCalled;
+ public static bool ConfigureContainerCalled;
+
+ public void ConfigureServices(IServiceCollection _) => ConfigureServicesCalled = true;
+ public void ConfigureContainer(MyContainerStruct _) => ConfigureContainerCalled = true;
+ public void Configure(IApplicationBuilder _) { }
+}
+
+public class MyContainerStructFactory : IServiceProviderFactory
+{
+ public MyContainerStruct CreateBuilder(IServiceCollection services) => new MyContainerStruct(services);
+
+ public IServiceProvider CreateServiceProvider(MyContainerStruct containerBuilder)
+ {
+ containerBuilder.Build();
+ return containerBuilder;
+ }
+}
+
+public struct MyContainerStruct : IServiceProvider
+{
+ private IServiceProvider _inner;
+ private IServiceCollection _services;
+
+ public MyContainerStruct(IServiceCollection services) => _services = services;
+ public void Build() => _inner = _services.BuildServiceProvider();
+ public object GetService(Type serviceType) => _inner.GetService(serviceType);
+}
diff --git a/src/Hosting/Hosting/src/Infrastructure/ISupportsStartup.cs b/src/Hosting/Hosting/src/Infrastructure/ISupportsStartup.cs
index cf4dedf93e6c..6ee6cce59e22 100644
--- a/src/Hosting/Hosting/src/Infrastructure/ISupportsStartup.cs
+++ b/src/Hosting/Hosting/src/Infrastructure/ISupportsStartup.cs
@@ -40,6 +40,6 @@ public interface ISupportsStartup
///
/// A delegate that specifies a factory for the startup class.
/// The .
- /// When using the IL linker, all public methods of are preserved. This should match the Startup type directly (and not a base type).
+ /// When in a trimmed app, all public methods of are preserved. This should match the Startup type directly (and not a base type).
IWebHostBuilder UseStartup<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] TStartup>(Func startupFactory);
}
diff --git a/src/Hosting/Hosting/src/WebHostBuilderExtensions.cs b/src/Hosting/Hosting/src/WebHostBuilderExtensions.cs
index 050b0c5f2ef8..af693bc07cea 100644
--- a/src/Hosting/Hosting/src/WebHostBuilderExtensions.cs
+++ b/src/Hosting/Hosting/src/WebHostBuilderExtensions.cs
@@ -86,7 +86,7 @@ public static IWebHostBuilder Configure(this IWebHostBuilder hostBuilder, Action
/// The to configure.
/// A delegate that specifies a factory for the startup class.
/// The .
- /// When using the il linker, all public methods of are preserved. This should match the Startup type directly (and not a base type).
+ /// When in a trimmed app, all public methods of are preserved. This should match the Startup type directly (and not a base type).
public static IWebHostBuilder UseStartup<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] TStartup>(this IWebHostBuilder hostBuilder, Func startupFactory) where TStartup : class
{
ArgumentNullException.ThrowIfNull(startupFactory);