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;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.ExceptionServices;
|
using System.Runtime.ExceptionServices;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Hosting.Builder;
|
using Microsoft.AspNetCore.Hosting.Builder;
|
||||||
|
using Microsoft.AspNetCore.Hosting.Internal;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
@ -196,7 +198,7 @@ namespace Microsoft.AspNetCore.Hosting
|
||||||
return this;
|
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.
|
// UseStartup can be called multiple times. Only run the last one.
|
||||||
_startupObject = startupType;
|
_startupObject = startupType;
|
||||||
|
|
@ -213,7 +215,7 @@ namespace Microsoft.AspNetCore.Hosting
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IWebHostBuilder UseStartup(Func<WebHostBuilderContext, object> startupFactory)
|
public IWebHostBuilder UseStartup<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]TStartup>(Func<WebHostBuilderContext, TStartup> startupFactory)
|
||||||
{
|
{
|
||||||
// Clear the startup type
|
// Clear the startup type
|
||||||
_startupObject = startupFactory;
|
_startupObject = startupFactory;
|
||||||
|
|
@ -232,7 +234,7 @@ namespace Microsoft.AspNetCore.Hosting
|
||||||
return this;
|
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 webHostBuilderContext = GetWebHostBuilderContext(context);
|
||||||
var webHostOptions = (WebHostOptions)context.Properties[typeof(WebHostOptions)];
|
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.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.AspNetCore.Hosting.Internal;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
|
@ -71,12 +73,12 @@ namespace Microsoft.AspNetCore.Hosting
|
||||||
return _builder.Configure(configure);
|
return _builder.Configure(configure);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IWebHostBuilder UseStartup(Type startupType)
|
public IWebHostBuilder UseStartup([DynamicallyAccessedMembers(StartupLinkerOptions.Accessibility)] Type startupType)
|
||||||
{
|
{
|
||||||
return _builder.UseStartup(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);
|
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.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.AspNetCore.Hosting.Internal;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Hosting
|
namespace Microsoft.AspNetCore.Hosting
|
||||||
{
|
{
|
||||||
internal interface ISupportsStartup
|
internal interface ISupportsStartup
|
||||||
{
|
{
|
||||||
IWebHostBuilder Configure(Action<WebHostBuilderContext, IApplicationBuilder> configure);
|
IWebHostBuilder Configure(Action<WebHostBuilderContext, IApplicationBuilder> configure);
|
||||||
IWebHostBuilder UseStartup(Type startupType);
|
IWebHostBuilder UseStartup([DynamicallyAccessedMembers(StartupLinkerOptions.Accessibility)] Type startupType);
|
||||||
IWebHostBuilder UseStartup(Func<WebHostBuilderContext, object> startupFactory);
|
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;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using Microsoft.AspNetCore.Hosting.Internal;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Hosting
|
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
|
// 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.
|
// 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);
|
var configureMethod = FindConfigureDelegate(startupType, environmentName);
|
||||||
|
|
||||||
|
|
@ -272,31 +274,31 @@ namespace Microsoft.AspNetCore.Hosting
|
||||||
return type;
|
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);
|
var configureMethod = FindMethod(startupType, "Configure{0}", environmentName, typeof(void), required: true);
|
||||||
return new ConfigureBuilder(configureMethod);
|
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);
|
var configureMethod = FindMethod(startupType, "Configure{0}Container", environmentName, typeof(void), required: false);
|
||||||
return new ConfigureContainerBuilder(configureMethod);
|
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);
|
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)
|
var servicesMethod = FindMethod(startupType, "Configure{0}Services", environmentName, typeof(IServiceProvider), required: false)
|
||||||
?? FindMethod(startupType, "Configure{0}Services", environmentName, typeof(void), required: false);
|
?? FindMethod(startupType, "Configure{0}Services", environmentName, typeof(void), required: false);
|
||||||
return new ConfigureServicesBuilder(servicesMethod);
|
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 methodNameWithEnv = string.Format(CultureInfo.InvariantCulture, methodName, environmentName);
|
||||||
var methodNameWithNoEnv = string.Format(CultureInfo.InvariantCulture, methodName, "");
|
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.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.AspNetCore.Hosting.Internal;
|
||||||
using Microsoft.AspNetCore.Hosting.StaticWebAssets;
|
using Microsoft.AspNetCore.Hosting.StaticWebAssets;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
@ -67,7 +69,8 @@ namespace Microsoft.AspNetCore.Hosting
|
||||||
/// <param name="hostBuilder">The <see cref="IWebHostBuilder"/> to configure.</param>
|
/// <param name="hostBuilder">The <see cref="IWebHostBuilder"/> to configure.</param>
|
||||||
/// <param name="startupFactory">A delegate that specifies a factory for the startup class.</param>
|
/// <param name="startupFactory">A delegate that specifies a factory for the startup class.</param>
|
||||||
/// <returns>The <see cref="IWebHostBuilder"/>.</returns>
|
/// <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)
|
if (startupFactory == null)
|
||||||
{
|
{
|
||||||
|
|
@ -110,7 +113,7 @@ namespace Microsoft.AspNetCore.Hosting
|
||||||
/// <param name="hostBuilder">The <see cref="IWebHostBuilder"/> to configure.</param>
|
/// <param name="hostBuilder">The <see cref="IWebHostBuilder"/> to configure.</param>
|
||||||
/// <param name="startupType">The <see cref="Type"/> to be used.</param>
|
/// <param name="startupType">The <see cref="Type"/> to be used.</param>
|
||||||
/// <returns>The <see cref="IWebHostBuilder"/>.</returns>
|
/// <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)
|
if (startupType == null)
|
||||||
{
|
{
|
||||||
|
|
@ -151,7 +154,7 @@ namespace Microsoft.AspNetCore.Hosting
|
||||||
/// <param name="hostBuilder">The <see cref="IWebHostBuilder"/> to configure.</param>
|
/// <param name="hostBuilder">The <see cref="IWebHostBuilder"/> to configure.</param>
|
||||||
/// <typeparam name ="TStartup">The type containing the startup methods for the application.</typeparam>
|
/// <typeparam name ="TStartup">The type containing the startup methods for the application.</typeparam>
|
||||||
/// <returns>The <see cref="IWebHostBuilder"/>.</returns>
|
/// <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));
|
return hostBuilder.UseStartup(typeof(TStartup));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,7 @@ namespace Microsoft.AspNetCore.Hosting.Tests.Fakes
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IWebHostBuilder UseStartup(Func<WebHostBuilderContext, object> startupFactory)
|
public IWebHostBuilder UseStartup<TStartup>(Func<WebHostBuilderContext, TStartup> startupFactory)
|
||||||
{
|
{
|
||||||
_builder.UseStartup(startupFactory);
|
_builder.UseStartup(startupFactory);
|
||||||
return this;
|
return this;
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,7 @@ namespace Microsoft.AspNetCore.Hosting
|
||||||
public void UseStartupThrowsWhenFactoryReturnsNull(IWebHostBuilder builder)
|
public void UseStartupThrowsWhenFactoryReturnsNull(IWebHostBuilder builder)
|
||||||
{
|
{
|
||||||
var server = new TestServer();
|
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);
|
Assert.Equal("The specified factory returned null startup instance.", ex.Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -96,7 +96,7 @@ namespace Microsoft.AspNetCore.Hosting
|
||||||
var server = new TestServer();
|
var server = new TestServer();
|
||||||
var host = builder.UseServer(server)
|
var host = builder.UseServer(server)
|
||||||
.UseStartup<StartupCtorThrows>()
|
.UseStartup<StartupCtorThrows>()
|
||||||
.UseStartup(context => throw new InvalidOperationException("This doesn't run"))
|
.UseStartup<object>(context => throw new InvalidOperationException("This doesn't run"))
|
||||||
.Configure(app =>
|
.Configure(app =>
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("This doesn't run");
|
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
|
// avoids triggering builds of dependencies of the test app which could cause issues like https://github.com/dotnet/arcade/issues/2941
|
||||||
+ $" --no-dependencies"
|
+ $" --no-dependencies"
|
||||||
+ $" /p:TargetArchitecture={deploymentParameters.RuntimeArchitecture}"
|
+ $" /p:TargetArchitecture={deploymentParameters.RuntimeArchitecture}"
|
||||||
+ " --no-restore";
|
+ (deploymentParameters.RestoreDependencies ? "" : " --no-restore");
|
||||||
|
|
||||||
if (deploymentParameters.ApplicationType == ApplicationType.Standalone)
|
if (deploymentParameters.ApplicationType == ApplicationType.Standalone)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -113,6 +113,8 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string ApplicationBaseUriHint { get; set; }
|
public string ApplicationBaseUriHint { get; set; }
|
||||||
|
|
||||||
|
public bool RestoreDependencies { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Scheme used by the deployed application if <see cref="ApplicationBaseUriHint"/> is empty.
|
/// Scheme used by the deployed application if <see cref="ApplicationBaseUriHint"/> is empty.
|
||||||
/// </summary>
|
/// </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.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Linq.Expressions;
|
using System.Linq.Expressions;
|
||||||
using System.Reflection;
|
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)!;
|
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>
|
/// <summary>
|
||||||
/// Adds a middleware type to the application's request pipeline.
|
/// Adds a middleware type to the application's request pipeline.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -29,7 +33,7 @@ namespace Microsoft.AspNetCore.Builder
|
||||||
/// <param name="app">The <see cref="IApplicationBuilder"/> instance.</param>
|
/// <param name="app">The <see cref="IApplicationBuilder"/> instance.</param>
|
||||||
/// <param name="args">The arguments to pass to the middleware type instance's constructor.</param>
|
/// <param name="args">The arguments to pass to the middleware type instance's constructor.</param>
|
||||||
/// <returns>The <see cref="IApplicationBuilder"/> instance.</returns>
|
/// <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);
|
return app.UseMiddleware(typeof(TMiddleware), args);
|
||||||
}
|
}
|
||||||
|
|
@ -41,7 +45,7 @@ namespace Microsoft.AspNetCore.Builder
|
||||||
/// <param name="middleware">The middleware type.</param>
|
/// <param name="middleware">The middleware type.</param>
|
||||||
/// <param name="args">The arguments to pass to the middleware type instance's constructor.</param>
|
/// <param name="args">The arguments to pass to the middleware type instance's constructor.</param>
|
||||||
/// <returns>The <see cref="IApplicationBuilder"/> instance.</returns>
|
/// <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()))
|
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 =>
|
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.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Extensions.Internal;
|
using Microsoft.Extensions.Internal;
|
||||||
|
|
||||||
|
|
@ -9,7 +10,7 @@ namespace Microsoft.AspNetCore.Connections
|
||||||
{
|
{
|
||||||
public static class ConnectionBuilderExtensions
|
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);
|
var handler = ActivatorUtilities.GetServiceOrCreateInstance<TConnectionHandler>(connectionBuilder.ApplicationServices);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
<Compile Include="$(SharedSourceRoot)ActivatorUtilities\*.cs" />
|
<Compile Include="$(SharedSourceRoot)ActivatorUtilities\*.cs" />
|
||||||
<Compile Include="$(SharedSourceRoot)ParameterDefaultValue\*.cs" />
|
<Compile Include="$(SharedSourceRoot)ParameterDefaultValue\*.cs" />
|
||||||
|
<Compile Include="$(SharedSourceRoot)CodeAnalysis\*.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
|
<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.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using Microsoft.AspNetCore.Connections;
|
using Microsoft.AspNetCore.Connections;
|
||||||
using Microsoft.AspNetCore.SignalR.Internal;
|
using Microsoft.AspNetCore.SignalR.Internal;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
@ -13,13 +14,15 @@ namespace Microsoft.AspNetCore.SignalR
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class SignalRConnectionBuilderExtensions
|
public static class SignalRConnectionBuilderExtensions
|
||||||
{
|
{
|
||||||
|
private const DynamicallyAccessedMemberTypes HubAccessibility = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.PublicMethods;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Configure the connection to host the specified <see cref="Hub"/> type.
|
/// Configure the connection to host the specified <see cref="Hub"/> type.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="THub">The <see cref="Hub"/> type to host on the connection.</typeparam>
|
/// <typeparam name="THub">The <see cref="Hub"/> type to host on the connection.</typeparam>
|
||||||
/// <param name="connectionBuilder">The connection to configure.</param>
|
/// <param name="connectionBuilder">The connection to configure.</param>
|
||||||
/// <returns>The same instance of the <see cref="IConnectionBuilder"/> for chaining.</returns>
|
/// <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));
|
var marker = connectionBuilder.ApplicationServices.GetService(typeof(SignalRCoreMarkerService));
|
||||||
if (marker == null)
|
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.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using Microsoft.AspNetCore.Http.Connections;
|
using Microsoft.AspNetCore.Http.Connections;
|
||||||
using Microsoft.AspNetCore.Routing;
|
using Microsoft.AspNetCore.Routing;
|
||||||
using Microsoft.AspNetCore.SignalR;
|
using Microsoft.AspNetCore.SignalR;
|
||||||
|
|
@ -11,6 +12,8 @@ namespace Microsoft.AspNetCore.Builder
|
||||||
{
|
{
|
||||||
public static class HubEndpointRouteBuilderExtensions
|
public static class HubEndpointRouteBuilderExtensions
|
||||||
{
|
{
|
||||||
|
private const DynamicallyAccessedMemberTypes HubAccessibility = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.PublicMethods;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Maps incoming requests with the specified path to the specified <see cref="Hub"/> type.
|
/// Maps incoming requests with the specified path to the specified <see cref="Hub"/> type.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -18,7 +21,7 @@ namespace Microsoft.AspNetCore.Builder
|
||||||
/// <param name="endpoints">The <see cref="IEndpointRouteBuilder"/> to add the route to.</param>
|
/// <param name="endpoints">The <see cref="IEndpointRouteBuilder"/> to add the route to.</param>
|
||||||
/// <param name="pattern">The route pattern.</param>
|
/// <param name="pattern">The route pattern.</param>
|
||||||
/// <returns>An <see cref="HubEndpointConventionBuilder"/> for endpoints associated with the connections.</returns>
|
/// <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);
|
return endpoints.MapHub<THub>(pattern, configureOptions: null);
|
||||||
}
|
}
|
||||||
|
|
@ -31,7 +34,7 @@ namespace Microsoft.AspNetCore.Builder
|
||||||
/// <param name="pattern">The route pattern.</param>
|
/// <param name="pattern">The route pattern.</param>
|
||||||
/// <param name="configureOptions">A callback to configure dispatcher options.</param>
|
/// <param name="configureOptions">A callback to configure dispatcher options.</param>
|
||||||
/// <returns>An <see cref="HubEndpointConventionBuilder"/> for endpoints associated with the connections.</returns>
|
/// <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>();
|
var marker = endpoints.ServiceProvider.GetService<SignalRMarkerService>();
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue