Dipping toes into linker friendliness (#24458)
- Annotated UseMiddleware and UseStartup to preserve constructors and public methods. - Annotated UseHub and MapHub preserve constructors and public methods. - Added a test to verify UseStartup and UseMiddleware works - The linker.xml preserves constructors all of the types that are registered in DI. This should be removed once we get the linker friendly DI changes.
This commit is contained in:
parent
dd25b5f91a
commit
404d817677
|
|
@ -4,11 +4,13 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.ExceptionServices;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting.Builder;
|
||||
using Microsoft.AspNetCore.Hosting.Internal;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
|
@ -196,7 +198,7 @@ namespace Microsoft.AspNetCore.Hosting
|
|||
return this;
|
||||
}
|
||||
|
||||
public IWebHostBuilder UseStartup(Type startupType)
|
||||
public IWebHostBuilder UseStartup([DynamicallyAccessedMembers(StartupLinkerOptions.Accessibility)] Type startupType)
|
||||
{
|
||||
// UseStartup can be called multiple times. Only run the last one.
|
||||
_startupObject = startupType;
|
||||
|
|
@ -213,7 +215,7 @@ namespace Microsoft.AspNetCore.Hosting
|
|||
return this;
|
||||
}
|
||||
|
||||
public IWebHostBuilder UseStartup(Func<WebHostBuilderContext, object> startupFactory)
|
||||
public IWebHostBuilder UseStartup<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]TStartup>(Func<WebHostBuilderContext, TStartup> startupFactory)
|
||||
{
|
||||
// Clear the startup type
|
||||
_startupObject = startupFactory;
|
||||
|
|
@ -232,7 +234,7 @@ namespace Microsoft.AspNetCore.Hosting
|
|||
return this;
|
||||
}
|
||||
|
||||
private void UseStartup(Type startupType, HostBuilderContext context, IServiceCollection services, object instance = null)
|
||||
private void UseStartup([DynamicallyAccessedMembers(StartupLinkerOptions.Accessibility)] Type startupType, HostBuilderContext context, IServiceCollection services, object instance = null)
|
||||
{
|
||||
var webHostBuilderContext = GetWebHostBuilderContext(context);
|
||||
var webHostOptions = (WebHostOptions)context.Properties[typeof(WebHostOptions)];
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting.Internal;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
|
|
@ -71,12 +73,12 @@ namespace Microsoft.AspNetCore.Hosting
|
|||
return _builder.Configure(configure);
|
||||
}
|
||||
|
||||
public IWebHostBuilder UseStartup(Type startupType)
|
||||
public IWebHostBuilder UseStartup([DynamicallyAccessedMembers(StartupLinkerOptions.Accessibility)] Type startupType)
|
||||
{
|
||||
return _builder.UseStartup(startupType);
|
||||
}
|
||||
|
||||
public IWebHostBuilder UseStartup(Func<WebHostBuilderContext, object> startupFactory)
|
||||
public IWebHostBuilder UseStartup<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]TStartup>(Func<WebHostBuilderContext, TStartup> startupFactory)
|
||||
{
|
||||
return _builder.UseStartup(startupFactory);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,14 +2,16 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting.Internal;
|
||||
|
||||
namespace Microsoft.AspNetCore.Hosting
|
||||
{
|
||||
internal interface ISupportsStartup
|
||||
{
|
||||
IWebHostBuilder Configure(Action<WebHostBuilderContext, IApplicationBuilder> configure);
|
||||
IWebHostBuilder UseStartup(Type startupType);
|
||||
IWebHostBuilder UseStartup(Func<WebHostBuilderContext, object> startupFactory);
|
||||
IWebHostBuilder UseStartup([DynamicallyAccessedMembers(StartupLinkerOptions.Accessibility)] Type startupType);
|
||||
IWebHostBuilder UseStartup<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]TStartup>(Func<WebHostBuilderContext, TStartup> startupFactory);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Microsoft.AspNetCore.Hosting.Internal
|
||||
{
|
||||
internal static class StartupLinkerOptions
|
||||
{
|
||||
// We're going to keep all public constructors and public methods on Startup classes
|
||||
public const DynamicallyAccessedMemberTypes Accessibility = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.PublicMethods;
|
||||
}
|
||||
}
|
||||
|
|
@ -3,9 +3,11 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Microsoft.AspNetCore.Hosting.Internal;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Microsoft.AspNetCore.Hosting
|
||||
|
|
@ -37,7 +39,7 @@ namespace Microsoft.AspNetCore.Hosting
|
|||
//
|
||||
// If the Startup class ConfigureServices returns an <see cref="IServiceProvider"/> and there is at least an <see cref="IStartupConfigureServicesFilter"/> registered we
|
||||
// throw as the filters can't be applied.
|
||||
public static StartupMethods LoadMethods(IServiceProvider hostingServiceProvider, Type startupType, string environmentName, object instance = null)
|
||||
public static StartupMethods LoadMethods(IServiceProvider hostingServiceProvider, [DynamicallyAccessedMembers(StartupLinkerOptions.Accessibility)] Type startupType, string environmentName, object instance = null)
|
||||
{
|
||||
var configureMethod = FindConfigureDelegate(startupType, environmentName);
|
||||
|
||||
|
|
@ -272,31 +274,31 @@ namespace Microsoft.AspNetCore.Hosting
|
|||
return type;
|
||||
}
|
||||
|
||||
internal static ConfigureBuilder FindConfigureDelegate(Type startupType, string environmentName)
|
||||
internal static ConfigureBuilder FindConfigureDelegate([DynamicallyAccessedMembers(StartupLinkerOptions.Accessibility)] Type startupType, string environmentName)
|
||||
{
|
||||
var configureMethod = FindMethod(startupType, "Configure{0}", environmentName, typeof(void), required: true);
|
||||
return new ConfigureBuilder(configureMethod);
|
||||
}
|
||||
|
||||
internal static ConfigureContainerBuilder FindConfigureContainerDelegate(Type startupType, string environmentName)
|
||||
internal static ConfigureContainerBuilder FindConfigureContainerDelegate([DynamicallyAccessedMembers(StartupLinkerOptions.Accessibility)] Type startupType, string environmentName)
|
||||
{
|
||||
var configureMethod = FindMethod(startupType, "Configure{0}Container", environmentName, typeof(void), required: false);
|
||||
return new ConfigureContainerBuilder(configureMethod);
|
||||
}
|
||||
|
||||
internal static bool HasConfigureServicesIServiceProviderDelegate(Type startupType, string environmentName)
|
||||
internal static bool HasConfigureServicesIServiceProviderDelegate([DynamicallyAccessedMembers(StartupLinkerOptions.Accessibility)] Type startupType, string environmentName)
|
||||
{
|
||||
return null != FindMethod(startupType, "Configure{0}Services", environmentName, typeof(IServiceProvider), required: false);
|
||||
}
|
||||
|
||||
internal static ConfigureServicesBuilder FindConfigureServicesDelegate(Type startupType, string environmentName)
|
||||
internal static ConfigureServicesBuilder FindConfigureServicesDelegate([DynamicallyAccessedMembers(StartupLinkerOptions.Accessibility)] Type startupType, string environmentName)
|
||||
{
|
||||
var servicesMethod = FindMethod(startupType, "Configure{0}Services", environmentName, typeof(IServiceProvider), required: false)
|
||||
?? FindMethod(startupType, "Configure{0}Services", environmentName, typeof(void), required: false);
|
||||
return new ConfigureServicesBuilder(servicesMethod);
|
||||
}
|
||||
|
||||
private static MethodInfo FindMethod(Type startupType, string methodName, string environmentName, Type returnType = null, bool required = true)
|
||||
private static MethodInfo FindMethod([DynamicallyAccessedMembers(StartupLinkerOptions.Accessibility)] Type startupType, string methodName, string environmentName, Type returnType = null, bool required = true)
|
||||
{
|
||||
var methodNameWithEnv = string.Format(CultureInfo.InvariantCulture, methodName, environmentName);
|
||||
var methodNameWithNoEnv = string.Format(CultureInfo.InvariantCulture, methodName, "");
|
||||
|
|
|
|||
|
|
@ -2,8 +2,10 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Reflection;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting.Internal;
|
||||
using Microsoft.AspNetCore.Hosting.StaticWebAssets;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
|
@ -67,7 +69,8 @@ namespace Microsoft.AspNetCore.Hosting
|
|||
/// <param name="hostBuilder">The <see cref="IWebHostBuilder"/> to configure.</param>
|
||||
/// <param name="startupFactory">A delegate that specifies a factory for the startup class.</param>
|
||||
/// <returns>The <see cref="IWebHostBuilder"/>.</returns>
|
||||
public static IWebHostBuilder UseStartup(this IWebHostBuilder hostBuilder, Func<WebHostBuilderContext, object> startupFactory)
|
||||
/// <remarks>When using the il linker, all public methods of <typeparamref name="TStartup"/> are preserved. This should match the Startup type directly (and not a base type).</remarks>
|
||||
public static IWebHostBuilder UseStartup<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]TStartup>(this IWebHostBuilder hostBuilder, Func<WebHostBuilderContext, TStartup> startupFactory) where TStartup : class
|
||||
{
|
||||
if (startupFactory == null)
|
||||
{
|
||||
|
|
@ -110,7 +113,7 @@ namespace Microsoft.AspNetCore.Hosting
|
|||
/// <param name="hostBuilder">The <see cref="IWebHostBuilder"/> to configure.</param>
|
||||
/// <param name="startupType">The <see cref="Type"/> to be used.</param>
|
||||
/// <returns>The <see cref="IWebHostBuilder"/>.</returns>
|
||||
public static IWebHostBuilder UseStartup(this IWebHostBuilder hostBuilder, Type startupType)
|
||||
public static IWebHostBuilder UseStartup(this IWebHostBuilder hostBuilder, [DynamicallyAccessedMembers(StartupLinkerOptions.Accessibility)] Type startupType)
|
||||
{
|
||||
if (startupType == null)
|
||||
{
|
||||
|
|
@ -151,7 +154,7 @@ namespace Microsoft.AspNetCore.Hosting
|
|||
/// <param name="hostBuilder">The <see cref="IWebHostBuilder"/> to configure.</param>
|
||||
/// <typeparam name ="TStartup">The type containing the startup methods for the application.</typeparam>
|
||||
/// <returns>The <see cref="IWebHostBuilder"/>.</returns>
|
||||
public static IWebHostBuilder UseStartup<TStartup>(this IWebHostBuilder hostBuilder) where TStartup : class
|
||||
public static IWebHostBuilder UseStartup<[DynamicallyAccessedMembers(StartupLinkerOptions.Accessibility)]TStartup>(this IWebHostBuilder hostBuilder) where TStartup : class
|
||||
{
|
||||
return hostBuilder.UseStartup(typeof(TStartup));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ namespace Microsoft.AspNetCore.Hosting.Tests.Fakes
|
|||
return this;
|
||||
}
|
||||
|
||||
public IWebHostBuilder UseStartup(Func<WebHostBuilderContext, object> startupFactory)
|
||||
public IWebHostBuilder UseStartup<TStartup>(Func<WebHostBuilderContext, TStartup> startupFactory)
|
||||
{
|
||||
_builder.UseStartup(startupFactory);
|
||||
return this;
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ namespace Microsoft.AspNetCore.Hosting
|
|||
public void UseStartupThrowsWhenFactoryReturnsNull(IWebHostBuilder builder)
|
||||
{
|
||||
var server = new TestServer();
|
||||
var ex = Assert.Throws<InvalidOperationException>(() => builder.UseServer(server).UseStartup(context => null).Build());
|
||||
var ex = Assert.Throws<InvalidOperationException>(() => builder.UseServer(server).UseStartup<object>(context => null).Build());
|
||||
Assert.Equal("The specified factory returned null startup instance.", ex.Message);
|
||||
}
|
||||
|
||||
|
|
@ -96,7 +96,7 @@ namespace Microsoft.AspNetCore.Hosting
|
|||
var server = new TestServer();
|
||||
var host = builder.UseServer(server)
|
||||
.UseStartup<StartupCtorThrows>()
|
||||
.UseStartup(context => throw new InvalidOperationException("This doesn't run"))
|
||||
.UseStartup<object>(context => throw new InvalidOperationException("This doesn't run"))
|
||||
.Configure(app =>
|
||||
{
|
||||
throw new InvalidOperationException("This doesn't run");
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
|
|||
// avoids triggering builds of dependencies of the test app which could cause issues like https://github.com/dotnet/arcade/issues/2941
|
||||
+ $" --no-dependencies"
|
||||
+ $" /p:TargetArchitecture={deploymentParameters.RuntimeArchitecture}"
|
||||
+ " --no-restore";
|
||||
+ (deploymentParameters.RestoreDependencies ? "" : " --no-restore");
|
||||
|
||||
if (deploymentParameters.ApplicationType == ApplicationType.Standalone)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -113,6 +113,8 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
|
|||
/// </summary>
|
||||
public string ApplicationBaseUriHint { get; set; }
|
||||
|
||||
public bool RestoreDependencies { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Scheme used by the deployed application if <see cref="ApplicationBaseUriHint"/> is empty.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,57 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Server.IntegrationTesting;
|
||||
using Microsoft.AspNetCore.Testing;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Hosting.FunctionalTests
|
||||
{
|
||||
public class LinkedApplicationTests : LoggedTest
|
||||
{
|
||||
[Fact]
|
||||
public async Task LinkedApplicationWorks()
|
||||
{
|
||||
using (StartLog(out var loggerFactory))
|
||||
{
|
||||
var logger = loggerFactory.CreateLogger("LinkedApplicationWorks");
|
||||
|
||||
// https://github.com/dotnet/aspnetcore/issues/8247
|
||||
#pragma warning disable 0618
|
||||
var applicationPath = Path.Combine(TestPathUtilities.GetSolutionRootDirectory("Hosting"), "test", "testassets",
|
||||
"BasicLinkedApp");
|
||||
#pragma warning restore 0618
|
||||
|
||||
var deploymentParameters = new DeploymentParameters(
|
||||
applicationPath,
|
||||
ServerType.Kestrel,
|
||||
RuntimeFlavor.CoreClr,
|
||||
RuntimeArchitecture.x64)
|
||||
{
|
||||
TargetFramework = Tfm.Net50,
|
||||
RuntimeArchitecture = RuntimeArchitecture.x64,
|
||||
ApplicationType = ApplicationType.Standalone,
|
||||
PublishApplicationBeforeDeployment = true,
|
||||
RestoreDependencies = true,
|
||||
StatusMessagesEnabled = false
|
||||
};
|
||||
|
||||
using var deployer = new SelfHostDeployer(deploymentParameters, loggerFactory);
|
||||
|
||||
var result = await deployer.DeployAsync();
|
||||
|
||||
// The app should have started up
|
||||
Assert.False(deployer.HostProcess.HasExited);
|
||||
|
||||
var response = await RetryHelper.RetryRequest(() => result.HttpClient.GetAsync("/"), logger, retryCount: 10);
|
||||
var body = await response.Content.ReadAsStringAsync();
|
||||
|
||||
Assert.Equal("Hello World", body);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
|
||||
<OutputType>Exe</OutputType>
|
||||
<PublishTrimmed>true</PublishTrimmed>
|
||||
<TrimMode>link</TrimMode>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.AspNetCore.Hosting" />
|
||||
<Reference Include="Microsoft.Extensions.Hosting" />
|
||||
<Reference Include="Microsoft.AspNetCore.Server.Kestrel" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<TrimmerRootDescriptor Include="Linker.xml" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Link all assemblies -->
|
||||
<Target Name="EnsureAllAssembliesAreLinked" BeforeTargets="PrepareForILLink">
|
||||
<ItemGroup>
|
||||
<ManagedAssemblyToLink>
|
||||
<TrimMode>link</TrimMode>
|
||||
</ManagedAssemblyToLink>
|
||||
<!-- Root this project assembly -->
|
||||
<TrimmerRootAssembly Include="$(TargetName)" />
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- See: https://github.com/mono/linker/blob/master/src/linker/README.md#syntax-of-xml-descriptor -->
|
||||
<linker>
|
||||
<assembly fullname="Microsoft.Extensions.Hosting">
|
||||
<type fullname="Microsoft.Extensions.Hosting.Internal.ApplicationLifetime" />
|
||||
<type fullname="Microsoft.Extensions.Hosting.Internal.ConsoleLifetime" />
|
||||
<type fullname="Microsoft.Extensions.Hosting.ConsoleLifetimeOptions" />
|
||||
<type fullname="Microsoft.Extensions.Hosting.Internal.Host" />
|
||||
<type fullname="Microsoft.Extensions.Hosting.HostOptions" />
|
||||
</assembly>
|
||||
<assembly fullname="Microsoft.Extensions.Logging">
|
||||
<type fullname="Microsoft.Extensions.Logging.LoggerFactory" />
|
||||
</assembly>
|
||||
<assembly fullname="Microsoft.Extensions.Logging.Configuration">
|
||||
<type fullname="Microsoft.Extensions.Logging.Configuration.LoggerProviderConfigurationFactory" />
|
||||
<type fullname="Microsoft.Extensions.Logging.Configuration.LoggerProviderConfigureOptions`2" />
|
||||
<type fullname="Microsoft.Extensions.Logging.Configuration.LoggerProviderOptionsChangeTokenSource`2" />
|
||||
<type fullname="Microsoft.Extensions.Logging.Configuration.LoggerProviderConfiguration`1" />
|
||||
</assembly>
|
||||
<assembly fullname="Microsoft.Extensions.Logging.Console" preserve="all" />
|
||||
<assembly fullname="Microsoft.AspNetCore.Hosting">
|
||||
<type fullname="Microsoft.AspNetCore.Hosting.GenericWebHostApplicationLifetime" />
|
||||
<type fullname="Microsoft.AspNetCore.Http.DefaultHttpContextFactory" />
|
||||
<type fullname="Microsoft.AspNetCore.Hosting.Builder.ApplicationBuilderFactory" />
|
||||
<type fullname="Microsoft.AspNetCore.Hosting.GenericWebHostService" />
|
||||
<type fullname="Microsoft.AspNetCore.Hosting.GenericWebHostServiceOptions" />
|
||||
</assembly>
|
||||
<assembly fullname="Microsoft.AspNetCore.Http">
|
||||
<type fullname="Microsoft.AspNetCore.Http.MiddlewareFactory" />
|
||||
</assembly>
|
||||
<assembly fullname="Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets">
|
||||
<type fullname="Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.SocketTransportFactory" />
|
||||
<type fullname="Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.SocketTransportOptions" />
|
||||
</assembly>
|
||||
<assembly fullname="Microsoft.AspNetCore.Server.Kestrel.Core">
|
||||
<type fullname="Microsoft.AspNetCore.Server.Kestrel.Core.Internal.KestrelServerOptionsSetup" />
|
||||
<type fullname="Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServer" />
|
||||
</assembly>
|
||||
<assembly fullname="Microsoft.Extensions.Options">
|
||||
<type fullname="Microsoft.Extensions.Options.OptionsCache`1" />
|
||||
<type fullname="Microsoft.Extensions.Options.OptionsFactory`1" />
|
||||
<type fullname="Microsoft.Extensions.Options.OptionsMonitor`1" />
|
||||
<type fullname="Microsoft.Extensions.Options.OptionsManager`1" />
|
||||
</assembly>
|
||||
</linker>
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace BasicLinkedApp
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
CreateWebHostBuilder(args).Build().Run();
|
||||
}
|
||||
|
||||
// Do not change the signature of this method. It's used for tests.
|
||||
private static IHostBuilder CreateWebHostBuilder(string[] args)
|
||||
{
|
||||
return new HostBuilder()
|
||||
.ConfigureHostConfiguration(config =>
|
||||
{
|
||||
config.AddCommandLine(args);
|
||||
})
|
||||
.ConfigureLogging(logging =>
|
||||
{
|
||||
logging.AddConsole();
|
||||
})
|
||||
.ConfigureWebHost(webHostBuilder =>
|
||||
{
|
||||
webHostBuilder.UseKestrel().UseStartup<Startup>();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BasicLinkedApp
|
||||
{
|
||||
public class Startup
|
||||
{
|
||||
public void Configure(IApplicationBuilder app)
|
||||
{
|
||||
app.UseMiddleware<HelloWorldMiddleware>();
|
||||
}
|
||||
}
|
||||
|
||||
public class HelloWorldMiddleware
|
||||
{
|
||||
public HelloWorldMiddleware(RequestDelegate next)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public Task InvokeAsync(HttpContext context)
|
||||
{
|
||||
return context.Response.WriteAsync("Hello World");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
|
|
@ -22,6 +23,9 @@ namespace Microsoft.AspNetCore.Builder
|
|||
|
||||
private static readonly MethodInfo GetServiceInfo = typeof(UseMiddlewareExtensions).GetMethod(nameof(GetService), BindingFlags.NonPublic | BindingFlags.Static)!;
|
||||
|
||||
// We're going to keep all public constructors and public methods on middleware
|
||||
private const DynamicallyAccessedMemberTypes MiddlewareAccessibility = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.PublicMethods;
|
||||
|
||||
/// <summary>
|
||||
/// Adds a middleware type to the application's request pipeline.
|
||||
/// </summary>
|
||||
|
|
@ -29,7 +33,7 @@ namespace Microsoft.AspNetCore.Builder
|
|||
/// <param name="app">The <see cref="IApplicationBuilder"/> instance.</param>
|
||||
/// <param name="args">The arguments to pass to the middleware type instance's constructor.</param>
|
||||
/// <returns>The <see cref="IApplicationBuilder"/> instance.</returns>
|
||||
public static IApplicationBuilder UseMiddleware<TMiddleware>(this IApplicationBuilder app, params object[] args)
|
||||
public static IApplicationBuilder UseMiddleware<[DynamicallyAccessedMembers(MiddlewareAccessibility)]TMiddleware>(this IApplicationBuilder app, params object[] args)
|
||||
{
|
||||
return app.UseMiddleware(typeof(TMiddleware), args);
|
||||
}
|
||||
|
|
@ -41,7 +45,7 @@ namespace Microsoft.AspNetCore.Builder
|
|||
/// <param name="middleware">The middleware type.</param>
|
||||
/// <param name="args">The arguments to pass to the middleware type instance's constructor.</param>
|
||||
/// <returns>The <see cref="IApplicationBuilder"/> instance.</returns>
|
||||
public static IApplicationBuilder UseMiddleware(this IApplicationBuilder app, Type middleware, params object[] args)
|
||||
public static IApplicationBuilder UseMiddleware(this IApplicationBuilder app, [DynamicallyAccessedMembers(MiddlewareAccessibility)] Type middleware, params object[] args)
|
||||
{
|
||||
if (typeof(IMiddleware).GetTypeInfo().IsAssignableFrom(middleware.GetTypeInfo()))
|
||||
{
|
||||
|
|
@ -110,7 +114,7 @@ namespace Microsoft.AspNetCore.Builder
|
|||
});
|
||||
}
|
||||
|
||||
private static IApplicationBuilder UseMiddlewareInterface(IApplicationBuilder app, Type middlewareType)
|
||||
private static IApplicationBuilder UseMiddlewareInterface(IApplicationBuilder app, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type middlewareType)
|
||||
{
|
||||
return app.Use(next =>
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Internal;
|
||||
|
||||
|
|
@ -9,7 +10,7 @@ namespace Microsoft.AspNetCore.Connections
|
|||
{
|
||||
public static class ConnectionBuilderExtensions
|
||||
{
|
||||
public static IConnectionBuilder UseConnectionHandler<TConnectionHandler>(this IConnectionBuilder connectionBuilder) where TConnectionHandler : ConnectionHandler
|
||||
public static IConnectionBuilder UseConnectionHandler<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)]TConnectionHandler>(this IConnectionBuilder connectionBuilder) where TConnectionHandler : ConnectionHandler
|
||||
{
|
||||
var handler = ActivatorUtilities.GetServiceOrCreateInstance<TConnectionHandler>(connectionBuilder.ApplicationServices);
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
<Compile Include="$(SharedSourceRoot)ActivatorUtilities\*.cs" />
|
||||
<Compile Include="$(SharedSourceRoot)ParameterDefaultValue\*.cs" />
|
||||
<Compile Include="$(SharedSourceRoot)CodeAnalysis\*.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
|
||||
|
|
|
|||
|
|
@ -0,0 +1,92 @@
|
|||
#if !NET5_0
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace System.Diagnostics.CodeAnalysis
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies the types of members that are dynamically accessed.
|
||||
///
|
||||
/// This enumeration has a <see cref="FlagsAttribute"/> attribute that allows a
|
||||
/// bitwise combination of its member values.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
internal enum DynamicallyAccessedMemberTypes
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies no members.
|
||||
/// </summary>
|
||||
None = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the default, parameterless public constructor.
|
||||
/// </summary>
|
||||
PublicParameterlessConstructor = 0x0001,
|
||||
|
||||
/// <summary>
|
||||
/// Specifies all public constructors.
|
||||
/// </summary>
|
||||
PublicConstructors = 0x0002 | PublicParameterlessConstructor,
|
||||
|
||||
/// <summary>
|
||||
/// Specifies all non-public constructors.
|
||||
/// </summary>
|
||||
NonPublicConstructors = 0x0004,
|
||||
|
||||
/// <summary>
|
||||
/// Specifies all public methods.
|
||||
/// </summary>
|
||||
PublicMethods = 0x0008,
|
||||
|
||||
/// <summary>
|
||||
/// Specifies all non-public methods.
|
||||
/// </summary>
|
||||
NonPublicMethods = 0x0010,
|
||||
|
||||
/// <summary>
|
||||
/// Specifies all public fields.
|
||||
/// </summary>
|
||||
PublicFields = 0x0020,
|
||||
|
||||
/// <summary>
|
||||
/// Specifies all non-public fields.
|
||||
/// </summary>
|
||||
NonPublicFields = 0x0040,
|
||||
|
||||
/// <summary>
|
||||
/// Specifies all public nested types.
|
||||
/// </summary>
|
||||
PublicNestedTypes = 0x0080,
|
||||
|
||||
/// <summary>
|
||||
/// Specifies all non-public nested types.
|
||||
/// </summary>
|
||||
NonPublicNestedTypes = 0x0100,
|
||||
|
||||
/// <summary>
|
||||
/// Specifies all public properties.
|
||||
/// </summary>
|
||||
PublicProperties = 0x0200,
|
||||
|
||||
/// <summary>
|
||||
/// Specifies all non-public properties.
|
||||
/// </summary>
|
||||
NonPublicProperties = 0x0400,
|
||||
|
||||
/// <summary>
|
||||
/// Specifies all public events.
|
||||
/// </summary>
|
||||
PublicEvents = 0x0800,
|
||||
|
||||
/// <summary>
|
||||
/// Specifies all non-public events.
|
||||
/// </summary>
|
||||
NonPublicEvents = 0x1000,
|
||||
|
||||
/// <summary>
|
||||
/// Specifies all members.
|
||||
/// </summary>
|
||||
All = ~None
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
#if !NET5_0
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace System.Diagnostics.CodeAnalysis
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates that certain members on a specified <see cref="Type"/> are accessed dynamically,
|
||||
/// for example through <see cref="System.Reflection"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This allows tools to understand which members are being accessed during the execution
|
||||
/// of a program.
|
||||
///
|
||||
/// This attribute is valid on members whose type is <see cref="Type"/> or <see cref="string"/>.
|
||||
///
|
||||
/// When this attribute is applied to a location of type <see cref="string"/>, the assumption is
|
||||
/// that the string represents a fully qualified type name.
|
||||
///
|
||||
/// If the attribute is applied to a method it's treated as a special case and it implies
|
||||
/// the attribute should be applied to the "this" parameter of the method. As such the attribute
|
||||
/// should only be used on instance methods of types assignable to System.Type (or string, but no methods
|
||||
/// will use it there).
|
||||
/// </remarks>
|
||||
[AttributeUsage(
|
||||
AttributeTargets.Field | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter |
|
||||
AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.Method,
|
||||
Inherited = false)]
|
||||
internal sealed class DynamicallyAccessedMembersAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DynamicallyAccessedMembersAttribute"/> class
|
||||
/// with the specified member types.
|
||||
/// </summary>
|
||||
/// <param name="memberTypes">The types of members dynamically accessed.</param>
|
||||
public DynamicallyAccessedMembersAttribute(DynamicallyAccessedMemberTypes memberTypes)
|
||||
{
|
||||
MemberTypes = memberTypes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="DynamicallyAccessedMemberTypes"/> which specifies the type
|
||||
/// of members dynamically accessed.
|
||||
/// </summary>
|
||||
public DynamicallyAccessedMemberTypes MemberTypes { get; }
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Microsoft.AspNetCore.Connections;
|
||||
using Microsoft.AspNetCore.SignalR.Internal;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
|
@ -13,13 +14,15 @@ namespace Microsoft.AspNetCore.SignalR
|
|||
/// </summary>
|
||||
public static class SignalRConnectionBuilderExtensions
|
||||
{
|
||||
private const DynamicallyAccessedMemberTypes HubAccessibility = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.PublicMethods;
|
||||
|
||||
/// <summary>
|
||||
/// Configure the connection to host the specified <see cref="Hub"/> type.
|
||||
/// </summary>
|
||||
/// <typeparam name="THub">The <see cref="Hub"/> type to host on the connection.</typeparam>
|
||||
/// <param name="connectionBuilder">The connection to configure.</param>
|
||||
/// <returns>The same instance of the <see cref="IConnectionBuilder"/> for chaining.</returns>
|
||||
public static IConnectionBuilder UseHub<THub>(this IConnectionBuilder connectionBuilder) where THub : Hub
|
||||
public static IConnectionBuilder UseHub<[DynamicallyAccessedMembers(HubAccessibility)]THub>(this IConnectionBuilder connectionBuilder) where THub : Hub
|
||||
{
|
||||
var marker = connectionBuilder.ApplicationServices.GetService(typeof(SignalRCoreMarkerService));
|
||||
if (marker == null)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Microsoft.AspNetCore.Http.Connections;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
|
|
@ -11,6 +12,8 @@ namespace Microsoft.AspNetCore.Builder
|
|||
{
|
||||
public static class HubEndpointRouteBuilderExtensions
|
||||
{
|
||||
private const DynamicallyAccessedMemberTypes HubAccessibility = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.PublicMethods;
|
||||
|
||||
/// <summary>
|
||||
/// Maps incoming requests with the specified path to the specified <see cref="Hub"/> type.
|
||||
/// </summary>
|
||||
|
|
@ -18,7 +21,7 @@ namespace Microsoft.AspNetCore.Builder
|
|||
/// <param name="endpoints">The <see cref="IEndpointRouteBuilder"/> to add the route to.</param>
|
||||
/// <param name="pattern">The route pattern.</param>
|
||||
/// <returns>An <see cref="HubEndpointConventionBuilder"/> for endpoints associated with the connections.</returns>
|
||||
public static HubEndpointConventionBuilder MapHub<THub>(this IEndpointRouteBuilder endpoints, string pattern) where THub : Hub
|
||||
public static HubEndpointConventionBuilder MapHub<[DynamicallyAccessedMembers(HubAccessibility)]THub>(this IEndpointRouteBuilder endpoints, string pattern) where THub : Hub
|
||||
{
|
||||
return endpoints.MapHub<THub>(pattern, configureOptions: null);
|
||||
}
|
||||
|
|
@ -31,7 +34,7 @@ namespace Microsoft.AspNetCore.Builder
|
|||
/// <param name="pattern">The route pattern.</param>
|
||||
/// <param name="configureOptions">A callback to configure dispatcher options.</param>
|
||||
/// <returns>An <see cref="HubEndpointConventionBuilder"/> for endpoints associated with the connections.</returns>
|
||||
public static HubEndpointConventionBuilder MapHub<THub>(this IEndpointRouteBuilder endpoints, string pattern, Action<HttpConnectionDispatcherOptions> configureOptions) where THub : Hub
|
||||
public static HubEndpointConventionBuilder MapHub<[DynamicallyAccessedMembers(HubAccessibility)]THub>(this IEndpointRouteBuilder endpoints, string pattern, Action<HttpConnectionDispatcherOptions> configureOptions) where THub : Hub
|
||||
{
|
||||
var marker = endpoints.ServiceProvider.GetService<SignalRMarkerService>();
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue