Skip to content

Enable trimming for middleware and friends #41373

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions eng/Dependencies.props
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ and are generated based on the last package release.
<LatestPackageReference Include="System.CommandLine.Experimental" />
<LatestPackageReference Include="System.ComponentModel" />
<LatestPackageReference Include="System.ComponentModel.Annotations" />
<LatestPackageReference Include="System.Configuration.ConfigurationManager" />
<LatestPackageReference Include="System.Diagnostics.DiagnosticSource" />
<LatestPackageReference Include="System.Diagnostics.EventLog" />
<LatestPackageReference Include="System.DirectoryServices.Protocols" />
Expand Down
25 changes: 25 additions & 0 deletions eng/TrimmableProjects.props
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
<TrimmableProject Include="Microsoft.AspNetCore.Routing.Abstractions" />
<TrimmableProject Include="Microsoft.AspNetCore.Routing" />
<TrimmableProject Include="Microsoft.AspNetCore.WebUtilities" />
<TrimmableProject Include="Microsoft.AspNetCore.Html.Abstractions" />
<TrimmableProject Include="Microsoft.AspNetCore.Connections.Abstractions" />
<TrimmableProject Include="Microsoft.AspNetCore.Server.HttpSys" />
<TrimmableProject Include="Microsoft.AspNetCore.Server.IISIntegration" />
Expand All @@ -37,7 +38,28 @@
<TrimmableProject Include="Microsoft.AspNetCore.Server.Kestrel.Transport.Quic" />
<TrimmableProject Include="Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets" />
<TrimmableProject Include="Microsoft.AspNetCore.Authorization" />
<TrimmableProject Include="Microsoft.AspNetCore.Cors" />
<TrimmableProject Include="Microsoft.AspNetCore.Diagnostics.Abstractions" />
<TrimmableProject Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" />
<TrimmableProject Include="Microsoft.AspNetCore.Diagnostics" />
<TrimmableProject Include="Microsoft.AspNetCore.HeaderPropagation" />
<TrimmableProject Include="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" />
<TrimmableProject Include="Microsoft.AspNetCore.Diagnostics.HealthChecks" />
<TrimmableProject Include="Microsoft.AspNetCore.HostFiltering" />
<TrimmableProject Include="Microsoft.AspNetCore.HttpLogging" />
<TrimmableProject Include="Microsoft.AspNetCore.HttpOverrides" />
<TrimmableProject Include="Microsoft.AspNetCore.HttpsPolicy" />
<TrimmableProject Include="Microsoft.AspNetCore.Localization.Routing" />
<TrimmableProject Include="Microsoft.AspNetCore.Localization" />
<TrimmableProject Include="Microsoft.AspNetCore.RateLimiting" />
<TrimmableProject Include="Microsoft.AspNetCore.ResponseCaching.Abstractions" />
<TrimmableProject Include="Microsoft.AspNetCore.ResponseCaching" />
<TrimmableProject Include="Microsoft.AspNetCore.ResponseCompression" />
<TrimmableProject Include="Microsoft.AspNetCore.Rewrite" />
<TrimmableProject Include="Microsoft.AspNetCore.SpaProxy" />
<TrimmableProject Include="Microsoft.AspNetCore.SpaServices.Extensions" />
<TrimmableProject Include="Microsoft.AspNetCore.StaticFiles" />
<TrimmableProject Include="Microsoft.AspNetCore.WebSockets" />
<TrimmableProject Include="Microsoft.AspNetCore.Components.Authorization" />
<TrimmableProject Include="Microsoft.AspNetCore.Components" />
<TrimmableProject Include="Microsoft.AspNetCore.Components.Forms" />
Expand All @@ -48,6 +70,9 @@
<TrimmableProject Include="Microsoft.AspNetCore.Components.Web" />
<TrimmableProject Include="Microsoft.Extensions.ObjectPool" />
<TrimmableProject Include="Microsoft.JSInterop" />
<TrimmableProject Include="Microsoft.Extensions.WebEncoders" />
<TrimmableProject Include="Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions" />
<TrimmableProject Include="Microsoft.Extensions.Diagnostics.HealthChecks" />
<TrimmableProject Include="Microsoft.Extensions.Features" />
</ItemGroup>
</Project>
4 changes: 4 additions & 0 deletions eng/Version.Details.xml
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,10 @@
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>c10154087e734fa58f08f2797e5d99404e9cd96b</Sha>
</Dependency>
<Dependency Name="System.Configuration.ConfigurationManager" Version="7.0.0-preview.5.22226.6">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>c10154087e734fa58f08f2797e5d99404e9cd96b</Sha>
</Dependency>
<Dependency Name="System.Diagnostics.DiagnosticSource" Version="7.0.0-preview.5.22226.6">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>c10154087e734fa58f08f2797e5d99404e9cd96b</Sha>
Expand Down
1 change: 1 addition & 0 deletions eng/Versions.props
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@
<MicrosoftExtensionsOptionsVersion>7.0.0-preview.5.22226.6</MicrosoftExtensionsOptionsVersion>
<MicrosoftExtensionsPrimitivesVersion>7.0.0-preview.5.22226.6</MicrosoftExtensionsPrimitivesVersion>
<MicrosoftInternalRuntimeAspNetCoreTransportVersion>7.0.0-preview.5.22226.6</MicrosoftInternalRuntimeAspNetCoreTransportVersion>
<SystemConfigurationConfigurationManagerVersion>7.0.0-preview.5.22226.6</SystemConfigurationConfigurationManagerVersion>
<SystemDiagnosticsDiagnosticSourceVersion>7.0.0-preview.5.22226.6</SystemDiagnosticsDiagnosticSourceVersion>
<SystemDiagnosticsEventLogVersion>7.0.0-preview.5.22226.6</SystemDiagnosticsEventLogVersion>
<SystemDirectoryServicesProtocolsVersion>7.0.0-preview.5.22226.6</SystemDirectoryServicesProtocolsVersion>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<Description>Abstractions for defining health checks in .NET applications
Expand All @@ -12,7 +12,7 @@ Microsoft.Extensions.Diagnostics.HealthChecks.IHealthCheck
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageTags>diagnostics;healthchecks</PackageTags>
<IsAspNetCoreApp>true</IsAspNetCoreApp>
<Nullable>enable</Nullable>
<IsTrimmable>true</IsTrimmable>
</PropertyGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ public static IHealthChecksBuilder AddCheck(
/// access to services from the dependency injection container.
/// </remarks>
// 2.0 BACKCOMPAT OVERLOAD -- DO NOT TOUCH
public static IHealthChecksBuilder AddCheck<T>(
public static IHealthChecksBuilder AddCheck<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] T>(
this IHealthChecksBuilder builder,
string name,
HealthStatus? failureStatus,
Expand Down Expand Up @@ -123,8 +123,7 @@ public static IHealthChecksBuilder AddCheck<T>(
/// with any lifetime it will be used. Otherwise an instance of type <typeparamref name="T"/> will be constructed with
/// access to services from the dependency injection container.
/// </remarks>
[SuppressMessage("ApiDesign", "RS0027:Public API with optional parameter(s) should have the most parameters amongst its public overloads.", Justification = "Required to maintain compatibility")]
public static IHealthChecksBuilder AddCheck<T>(
public static IHealthChecksBuilder AddCheck<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] T>(
this IHealthChecksBuilder builder,
string name,
HealthStatus? failureStatus = null,
Expand All @@ -141,7 +140,12 @@ public static IHealthChecksBuilder AddCheck<T>(
throw new ArgumentNullException(nameof(name));
}

return builder.Add(new HealthCheckRegistration(name, s => ActivatorUtilities.GetServiceOrCreateInstance<T>(s), failureStatus, tags, timeout));
return builder.Add(new HealthCheckRegistration(name, GetServiceOrCreateInstance, failureStatus, tags, timeout));

[UnconditionalSuppressMessage("Trimming", "IL2091",
Justification = "DynamicallyAccessedMemberTypes.PublicConstructors is enforced by calling method.")]
static T GetServiceOrCreateInstance(IServiceProvider serviceProvider) =>
ActivatorUtilities.GetServiceOrCreateInstance<T>(serviceProvider);
}

// NOTE: AddTypeActivatedCheck has overloads rather than default parameters values, because default parameter values don't
Expand All @@ -159,7 +163,9 @@ public static IHealthChecksBuilder AddCheck<T>(
/// This method will use <see cref="ActivatorUtilities.CreateInstance{T}(IServiceProvider, object[])"/> to create the health check
/// instance when needed. Additional arguments can be provided to the constructor via <paramref name="args"/>.
/// </remarks>
public static IHealthChecksBuilder AddTypeActivatedCheck<T>(this IHealthChecksBuilder builder, string name, params object[] args) where T : class, IHealthCheck
public static IHealthChecksBuilder AddTypeActivatedCheck<
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] T>(
this IHealthChecksBuilder builder, string name, params object[] args) where T : class, IHealthCheck
{
if (builder == null)
{
Expand Down Expand Up @@ -190,7 +196,8 @@ public static IHealthChecksBuilder AddTypeActivatedCheck<T>(this IHealthChecksBu
/// This method will use <see cref="ActivatorUtilities.CreateInstance{T}(IServiceProvider, object[])"/> to create the health check
/// instance when needed. Additional arguments can be provided to the constructor via <paramref name="args"/>.
/// </remarks>
public static IHealthChecksBuilder AddTypeActivatedCheck<T>(
public static IHealthChecksBuilder AddTypeActivatedCheck<
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] T>(
this IHealthChecksBuilder builder,
string name,
HealthStatus? failureStatus,
Expand Down Expand Up @@ -226,7 +233,8 @@ public static IHealthChecksBuilder AddTypeActivatedCheck<T>(
/// This method will use <see cref="ActivatorUtilities.CreateInstance{T}(IServiceProvider, object[])"/> to create the health check
/// instance when needed. Additional arguments can be provided to the constructor via <paramref name="args"/>.
/// </remarks>
public static IHealthChecksBuilder AddTypeActivatedCheck<T>(
public static IHealthChecksBuilder AddTypeActivatedCheck<
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] T>(
this IHealthChecksBuilder builder,
string name,
HealthStatus? failureStatus,
Expand All @@ -243,7 +251,12 @@ public static IHealthChecksBuilder AddTypeActivatedCheck<T>(
throw new ArgumentNullException(nameof(name));
}

return builder.Add(new HealthCheckRegistration(name, s => ActivatorUtilities.CreateInstance<T>(s, args), failureStatus, tags));
return builder.Add(new HealthCheckRegistration(name, CreateInstance, failureStatus, tags));

[UnconditionalSuppressMessage("Trimming", "IL2091",
Justification = "DynamicallyAccessedMemberTypes.PublicConstructors is enforced by calling method.")]
T CreateInstance(IServiceProvider serviceProvider) =>
ActivatorUtilities.CreateInstance<T>(serviceProvider, args);
}

/// <summary>
Expand All @@ -264,7 +277,8 @@ public static IHealthChecksBuilder AddTypeActivatedCheck<T>(
/// This method will use <see cref="ActivatorUtilities.CreateInstance{T}(IServiceProvider, object[])"/> to create the health check
/// instance when needed. Additional arguments can be provided to the constructor via <paramref name="args"/>.
/// </remarks>
public static IHealthChecksBuilder AddTypeActivatedCheck<T>(
public static IHealthChecksBuilder AddTypeActivatedCheck<
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] T>(
this IHealthChecksBuilder builder,
string name,
HealthStatus? failureStatus,
Expand All @@ -282,6 +296,10 @@ public static IHealthChecksBuilder AddTypeActivatedCheck<T>(
throw new ArgumentNullException(nameof(name));
}

return builder.Add(new HealthCheckRegistration(name, s => ActivatorUtilities.CreateInstance<T>(s, args), failureStatus, tags, timeout));
return builder.Add(new HealthCheckRegistration(name, CreateInstance, failureStatus, tags, timeout));

[UnconditionalSuppressMessage("Trimming", "IL2091",
Justification = "DynamicallyAccessedMemberTypes.PublicConstructors is enforced by calling method.")]
T CreateInstance(IServiceProvider serviceProvider) => ActivatorUtilities.CreateInstance<T>(serviceProvider, args);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@ Microsoft.Extensions.Diagnostics.HealthChecks.IHealthChecksBuilder
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageTags>diagnostics;healthchecks</PackageTags>
<IsAspNetCoreApp>true</IsAspNetCoreApp>
<Nullable>enable</Nullable>
<!-- workaround https://github.com/dotnet/roslyn/issues/52527 -->
<NoWarn>$(NoWarn);SYSLIB1006</NoWarn>
<IsTrimmable>true</IsTrimmable>
</PropertyGroup>

<ItemGroup>
Expand All @@ -23,6 +21,9 @@ Microsoft.Extensions.Diagnostics.HealthChecks.IHealthChecksBuilder
<ItemGroup>
<Compile Include="$(SharedSourceRoot)NonCapturingTimer\*.cs" />
<Compile Include="$(SharedSourceRoot)ValueStopwatch\*.cs" />

<Compile Include="$(SharedSourceRoot)TrimmingAttributes.cs" LinkBase="Shared"
Condition="'$(TargetFramework)' != '$(DefaultNetCoreTargetFramework)'" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Microsoft.AspNetCore.Html.IHtmlContent</Description>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageTags>aspnetcore</PackageTags>
<IsPackable>false</IsPackable>
<Nullable>enable</Nullable>
<IsTrimmable>true</IsTrimmable>
</PropertyGroup>

</Project>
2 changes: 1 addition & 1 deletion src/Middleware/CORS/src/Microsoft.AspNetCore.Cors.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Microsoft.AspNetCore.Cors.EnableCorsAttribute</Description>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageTags>aspnetcore;cors</PackageTags>
<IsPackable>false</IsPackable>
<Nullable>enable</Nullable>
<IsTrimmable>true</IsTrimmable>
</PropertyGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageTags>aspnetcore;diagnostics</PackageTags>
<IsPackable>false</IsPackable>
<Nullable>enable</Nullable>
<IsTrimmable>true</IsTrimmable>
</PropertyGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageTags>aspnetcore;diagnostics;entityframeworkcore</PackageTags>
<Nullable>enable</Nullable>
<IsTrimmable>true</IsTrimmable>
</PropertyGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,9 @@ private async Task InvokeCore(HttpContext context)
var registeredContexts = context.RequestServices.GetServices<DbContextOptions>()
.Select(o => o.ContextType);

if (!registeredContexts.Any(c => string.Equals(contextTypeName, c.AssemblyQualifiedName)))
var contextType = registeredContexts.FirstOrDefault(c => string.Equals(contextTypeName, c.AssemblyQualifiedName, StringComparison.Ordinal));

if (contextType is null)
{
var message = Strings.FormatMigrationsEndPointMiddleware_ContextNotRegistered(contextTypeName);

Expand All @@ -132,8 +134,6 @@ private async Task InvokeCore(HttpContext context)
return null;
}

var contextType = Type.GetType(contextTypeName)!;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Breaking change?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe not? The current code expects contextTypeName to match an exact FQN but doesn't use the resulting match: https://github.com/dotnet/aspnetcore/blob/main/src/Middleware/Diagnostics.EntityFrameworkCore/src/MigrationsEndPointMiddleware.cs#L121-L135.


var db = (DbContext?)context.RequestServices.GetService(contextType);

return db;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Text;
using Microsoft.AspNetCore.Builder;
Expand Down Expand Up @@ -115,9 +116,10 @@ public async Task Invoke(HttpContext context)

await _exceptionHandler(new ErrorContext(context, ex));

if (_diagnosticSource.IsEnabled("Microsoft.AspNetCore.Diagnostics.UnhandledException"))
const string eventName = "Microsoft.AspNetCore.Diagnostics.UnhandledException";
if (_diagnosticSource.IsEnabled(eventName))
{
_diagnosticSource.Write("Microsoft.AspNetCore.Diagnostics.UnhandledException", new { httpContext = context, exception = ex });
WriteDiagnosticEvent(_diagnosticSource, eventName, new { httpContext = context, exception = ex });
}

return;
Expand All @@ -129,6 +131,11 @@ public async Task Invoke(HttpContext context)
}
throw;
}

[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026",
Justification = "The values being passed into Write have the commonly used properties being preserved with DynamicDependency.")]
static void WriteDiagnosticEvent<TValue>(DiagnosticSource diagnosticSource, string name, TValue value)
=> diagnosticSource.Write(name, value);
}

// Assumes the response headers have not been sent. If they have, still attempt to write to the body.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.ExceptionServices;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
Expand Down Expand Up @@ -135,9 +136,10 @@ private async Task HandleException(HttpContext context, ExceptionDispatchInfo ed
// If the response has already started, assume exception handler was successful.
if (context.Response.HasStarted || context.Response.StatusCode != StatusCodes.Status404NotFound || _options.AllowStatusCode404Response)
{
if (_diagnosticListener.IsEnabled() && _diagnosticListener.IsEnabled("Microsoft.AspNetCore.Diagnostics.HandledException"))
const string eventName = "Microsoft.AspNetCore.Diagnostics.HandledException";
if (_diagnosticListener.IsEnabled() && _diagnosticListener.IsEnabled(eventName))
{
_diagnosticListener.Write("Microsoft.AspNetCore.Diagnostics.HandledException", new { httpContext = context, exception = edi.SourceException });
WriteDiagnosticEvent(_diagnosticListener, eventName, new { httpContext = context, exception = edi.SourceException });
}

return;
Expand All @@ -158,6 +160,11 @@ private async Task HandleException(HttpContext context, ExceptionDispatchInfo ed
}

edi.Throw(); // Re-throw wrapped exception or the original if we couldn't handle it

[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026",
Justification = "The values being passed into Write have the commonly used properties being preserved with DynamicDependency.")]
static void WriteDiagnosticEvent<TValue>(DiagnosticSource diagnosticSource, string name, TValue value)
=> diagnosticSource.Write(name, value);
}

private static void ClearHttpContext(HttpContext context)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageTags>aspnetcore;diagnostics</PackageTags>
<IsPackable>false</IsPackable>
<Nullable>enable</Nullable>
<IsTrimmable>true</IsTrimmable>
</PropertyGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageTags>aspnetcore;httpclient</PackageTags>
<Nullable>enable</Nullable>
<IsTrimmable>true</IsTrimmable>
</PropertyGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageTags>diagnostics;healthchecks;entityframeworkcore</PackageTags>
<BaseNamespace>Microsoft.Extensions.Diagnostics.HealthChecks</BaseNamespace>
<Nullable>enable</Nullable>
<IsTrimmable>true</IsTrimmable>
</PropertyGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageTags>diagnostics;healthchecks</PackageTags>
<IsPackable>false</IsPackable>
<Nullable>enable</Nullable>
<IsTrimmable>true</IsTrimmable>
</PropertyGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageTags>aspnetcore</PackageTags>
<IsPackable>false</IsPackable>
<Nullable>enable</Nullable>
<IsTrimmable>true</IsTrimmable>
</PropertyGroup>

<ItemGroup>
Expand Down
Loading