Skip to content

Commit bc6d8b5

Browse files
Zeegaanelit0451
andauthored
v9: Throw error on duplicate routes (#11774)
* Add conflicting route service and check * Added testclass * Cleanup * Update src/Umbraco.Web.BackOffice/Services/ConflictingRouteService.cs Co-authored-by: Elitsa Marinovska <[email protected]> * Implemented out variable Co-authored-by: Elitsa Marinovska <[email protected]> Co-authored-by: Elitsa Marinovska <[email protected]>
1 parent 1af09c7 commit bc6d8b5

File tree

6 files changed

+93
-1
lines changed

6 files changed

+93
-1
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace Umbraco.Cms.Core.Services
2+
{
3+
public interface IConflictingRouteService
4+
{
5+
public bool HasConflictingRoutes(out string controllerName);
6+
}
7+
}

src/Umbraco.Infrastructure/Runtime/RuntimeState.cs

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Threading;
4+
using Microsoft.Extensions.DependencyInjection;
45
using Microsoft.Extensions.Logging;
56
using Microsoft.Extensions.Options;
67
using Umbraco.Cms.Core;
@@ -12,6 +13,7 @@
1213
using Umbraco.Cms.Core.Services;
1314
using Umbraco.Cms.Infrastructure.Migrations.Upgrade;
1415
using Umbraco.Cms.Infrastructure.Persistence;
16+
using Umbraco.Cms.Web.Common.DependencyInjection;
1517
using Umbraco.Extensions;
1618

1719
namespace Umbraco.Cms.Infrastructure.Runtime
@@ -30,6 +32,7 @@ public class RuntimeState : IRuntimeState
3032
private readonly ILogger<RuntimeState> _logger;
3133
private readonly PendingPackageMigrations _packageMigrationState;
3234
private readonly Dictionary<string, object> _startupState = new Dictionary<string, object>();
35+
private readonly IConflictingRouteService _conflictingRouteService;
3336

3437
/// <summary>
3538
/// The initial <see cref="RuntimeState"/>
@@ -51,16 +54,35 @@ public RuntimeState(
5154
IUmbracoDatabaseFactory databaseFactory,
5255
ILogger<RuntimeState> logger,
5356
PendingPackageMigrations packageMigrationState)
57+
: this(
58+
globalSettings,
59+
unattendedSettings,
60+
umbracoVersion,
61+
databaseFactory,
62+
logger,
63+
packageMigrationState,
64+
StaticServiceProvider.Instance.GetRequiredService<IConflictingRouteService>())
65+
{
66+
}
67+
68+
public RuntimeState(
69+
IOptions<GlobalSettings> globalSettings,
70+
IOptions<UnattendedSettings> unattendedSettings,
71+
IUmbracoVersion umbracoVersion,
72+
IUmbracoDatabaseFactory databaseFactory,
73+
ILogger<RuntimeState> logger,
74+
PendingPackageMigrations packageMigrationState,
75+
IConflictingRouteService conflictingRouteService)
5476
{
5577
_globalSettings = globalSettings;
5678
_unattendedSettings = unattendedSettings;
5779
_umbracoVersion = umbracoVersion;
5880
_databaseFactory = databaseFactory;
5981
_logger = logger;
6082
_packageMigrationState = packageMigrationState;
83+
_conflictingRouteService = conflictingRouteService;
6184
}
6285

63-
6486
/// <inheritdoc />
6587
public Version Version => _umbracoVersion.Version;
6688

@@ -101,6 +123,16 @@ public void DetermineRuntimeLevel()
101123
return;
102124
}
103125

126+
// Check if we have multiple controllers with the same name.
127+
if (_conflictingRouteService.HasConflictingRoutes(out string controllerName))
128+
{
129+
Level = RuntimeLevel.BootFailed;
130+
Reason = RuntimeLevelReason.BootFailedOnException;
131+
BootFailedException = new BootFailedException($"Conflicting routes, you cannot have multiple controllers with the same name: {controllerName}");
132+
133+
return;
134+
}
135+
104136
// Check the database state, whether we can connect or if it's in an upgrade or empty state, etc...
105137

106138
switch (GetUmbracoDatabaseState(_databaseFactory))

src/Umbraco.Web.BackOffice/DependencyInjection/UmbracoBuilderExtensions.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ public static IUmbracoBuilder AddBackOfficeCore(this IUmbracoBuilder builder)
114114
});
115115

116116
builder.Services.AddUnique<IIconService, IconService>();
117+
builder.Services.AddUnique<IConflictingRouteService, ConflictingRouteService>();
117118
builder.Services.AddUnique<UnhandledExceptionLoggerMiddleware>();
118119

119120
return builder;
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
using System;
2+
using System.Linq;
3+
using Umbraco.Cms.Core.Composing;
4+
using Umbraco.Cms.Core.Services;
5+
using Umbraco.Cms.Web.Common.Controllers;
6+
7+
namespace Umbraco.Cms.Web.BackOffice.Services
8+
{
9+
public class ConflictingRouteService : IConflictingRouteService
10+
{
11+
private readonly TypeLoader _typeLoader;
12+
13+
/// <summary>
14+
/// Initializes a new instance of the <see cref="ConflictingRouteService"/> class.
15+
/// </summary>
16+
public ConflictingRouteService(TypeLoader typeLoader) => _typeLoader = typeLoader;
17+
18+
/// <inheritdoc/>
19+
public bool HasConflictingRoutes(out string controllerName)
20+
{
21+
var controllers = _typeLoader.GetTypes<UmbracoApiControllerBase>().ToList();
22+
foreach (Type controller in controllers)
23+
{
24+
if (controllers.Count(x => x.Name == controller.Name) > 1)
25+
{
26+
controllerName = controller.Name;
27+
return true;
28+
}
29+
}
30+
31+
controllerName = string.Empty;
32+
return false;
33+
}
34+
}
35+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using System;
2+
using Umbraco.Cms.Core.Services;
3+
4+
namespace Umbraco.Cms.Tests.Integration.Testing
5+
{
6+
public class TestConflictingRouteService : IConflictingRouteService
7+
{
8+
public bool HasConflictingRoutes(out string controllername)
9+
{
10+
controllername = string.Empty;
11+
return false;
12+
}
13+
}
14+
}

tests/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,9 @@ public virtual void ConfigureServices(IServiceCollection services)
201201
IWebHostEnvironment webHostEnvironment = TestHelper.GetWebHostEnvironment();
202202
services.AddRequiredNetCoreServices(TestHelper, webHostEnvironment);
203203

204+
// We register this service because we need it for IRuntimeState, if we don't this breaks 900 tests
205+
services.AddSingleton<IConflictingRouteService, TestConflictingRouteService>();
206+
204207
// Add it!
205208
Core.Hosting.IHostingEnvironment hostingEnvironment = TestHelper.GetHostingEnvironment();
206209
TypeLoader typeLoader = services.AddTypeLoader(

0 commit comments

Comments
 (0)