Skip to content

Commit fb0b099

Browse files
authored
Fixed de-duping hosting startup assemblies (#31440)
- De-dupe hosting startup assemblies based on assembly instance not the name of the assembly. Names can be short or long and we don't know if they resolve to the same assembly. Instead of trying to mess with names, we just check to make sure that the instance isn't the same.
1 parent c5a1999 commit fb0b099

File tree

4 files changed

+49
-3
lines changed

4 files changed

+49
-3
lines changed

src/Hosting/Hosting/src/GenericHost/GenericWebHostBuilder.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,15 +129,23 @@ private void ExecuteHostingStartups()
129129
}
130130

131131
var exceptions = new List<Exception>();
132+
var processed = new HashSet<Assembly>();
133+
132134
_hostingStartupWebHostBuilder = new HostingStartupWebHostBuilder(this);
133135

134136
// Execute the hosting startup assemblies
135-
foreach (var assemblyName in webHostOptions.GetFinalHostingStartupAssemblies().Distinct(StringComparer.OrdinalIgnoreCase))
137+
foreach (var assemblyName in webHostOptions.GetFinalHostingStartupAssemblies())
136138
{
137139
try
138140
{
139141
var assembly = Assembly.Load(new AssemblyName(assemblyName));
140142

143+
if (!processed.Add(assembly))
144+
{
145+
// Already processed, skip it
146+
continue;
147+
}
148+
141149
foreach (var attribute in assembly.GetCustomAttributes<HostingStartupAttribute>())
142150
{
143151
var hostingStartup = (IHostingStartup)Activator.CreateInstance(attribute.HostingStartupType)!;

src/Hosting/Hosting/src/WebHostBuilder.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,14 +229,21 @@ private IServiceCollection BuildCommonServices(out AggregateException? hostingSt
229229
if (!_options.PreventHostingStartup)
230230
{
231231
var exceptions = new List<Exception>();
232+
var processed = new HashSet<Assembly>();
232233

233234
// Execute the hosting startup assemblies
234-
foreach (var assemblyName in _options.GetFinalHostingStartupAssemblies().Distinct(StringComparer.OrdinalIgnoreCase))
235+
foreach (var assemblyName in _options.GetFinalHostingStartupAssemblies())
235236
{
236237
try
237238
{
238239
var assembly = Assembly.Load(new AssemblyName(assemblyName));
239240

241+
if (!processed.Add(assembly))
242+
{
243+
// Already processed, skip it
244+
continue;
245+
}
246+
240247
foreach (var attribute in assembly.GetCustomAttributes<HostingStartupAttribute>())
241248
{
242249
var hostingStartup = (IHostingStartup)Activator.CreateInstance(attribute.HostingStartupType)!;

src/Hosting/Hosting/test/WebHostBuilderTests.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -903,6 +903,27 @@ public void Build_RunsHostingStartupAssembliesIfSpecified(IWebHostBuilder builde
903903
using (var host = builder.Build())
904904
{
905905
Assert.Equal("1", builder.GetSetting("testhostingstartup1"));
906+
Assert.Equal("1", builder.GetSetting("testhostingstartup1_calls"));
907+
}
908+
}
909+
910+
[Theory]
911+
[MemberData(nameof(DefaultWebHostBuildersWithConfig))]
912+
public void Build_RunsDeduplicatedHostingStartupAssembliesIfSpecified(IWebHostBuilder builder)
913+
{
914+
var fullName = typeof(TestStartupAssembly1.TestHostingStartup1).Assembly.FullName;
915+
var name = typeof(TestStartupAssembly1.TestHostingStartup1).Assembly.GetName().Name;
916+
917+
builder = builder
918+
.CaptureStartupErrors(false)
919+
.UseSetting(WebHostDefaults.HostingStartupAssembliesKey, fullName + ";" + name)
920+
.Configure(app => { })
921+
.UseServer(new TestServer());
922+
923+
using (var host = builder.Build())
924+
{
925+
Assert.Equal("1", builder.GetSetting("testhostingstartup1"));
926+
Assert.Equal("1", builder.GetSetting("testhostingstartup1_calls"));
906927
}
907928
}
908929

src/Hosting/test/testassets/TestStartupAssembly1/TestHostingStartup1.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
// Copyright (c) .NET Foundation. All rights reserved.
1+
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

4+
using System.Globalization;
45
using Microsoft.AspNetCore.Hosting;
56

67
[assembly: HostingStartup(typeof(TestStartupAssembly1.TestHostingStartup1))]
@@ -11,8 +12,17 @@ public class TestHostingStartup1 : IHostingStartup
1112
{
1213
public void Configure(IWebHostBuilder builder)
1314
{
15+
var calls = builder.GetSetting("testhostingstartup1_calls");
16+
var numCalls = 1;
17+
18+
if (calls != null)
19+
{
20+
numCalls = int.Parse(calls, CultureInfo.InvariantCulture) + 1;
21+
}
22+
1423
builder.UseSetting("testhostingstartup1", "1");
1524
builder.UseSetting("testhostingstartup_chain", builder.GetSetting("testhostingstartup_chain") + "1");
25+
builder.UseSetting("testhostingstartup1_calls", numCalls.ToString(CultureInfo.InvariantCulture));
1626
}
1727
}
1828
}

0 commit comments

Comments
 (0)