Skip to content

Commit 69ab6ce

Browse files
committed
Only register IoC services when not already provided
1 parent 27249fb commit 69ab6ce

File tree

12 files changed

+52
-59
lines changed

12 files changed

+52
-59
lines changed

src/Examples/GettingStarted/Program.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@
22
using JsonApiDotNetCore.Configuration;
33
using JsonApiDotNetCore.MongoDb.Configuration;
44
using JsonApiDotNetCore.MongoDb.Repositories;
5+
using Microsoft.Extensions.DependencyInjection.Extensions;
56
using MongoDB.Driver;
67

78
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
89

910
// Add services to the container.
1011

11-
builder.Services.AddSingleton(_ =>
12+
builder.Services.TryAddSingleton(_ =>
1213
{
1314
var client = new MongoClient(builder.Configuration.GetSection("DatabaseSettings:ConnectionString").Value);
1415
return client.GetDatabase(builder.Configuration.GetSection("DatabaseSettings:Database").Value);

src/Examples/JsonApiDotNetCoreMongoDbExample/Program.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,19 +22,19 @@
2222
builder.Services.TryAddSingleton(TimeProvider.System);
2323
#endif
2424

25-
builder.Services.AddSingleton(_ =>
25+
builder.Services.TryAddSingleton(_ =>
2626
{
2727
var client = new MongoClient(builder.Configuration.GetValue<string>("DatabaseSettings:ConnectionString"));
2828
return client.GetDatabase(builder.Configuration.GetValue<string>("DatabaseSettings:Database"));
2929
});
3030

31+
builder.Services.TryAddScoped(typeof(IResourceReadRepository<,>), typeof(MongoRepository<,>));
32+
builder.Services.TryAddScoped(typeof(IResourceWriteRepository<,>), typeof(MongoRepository<,>));
33+
builder.Services.TryAddScoped(typeof(IResourceRepository<,>), typeof(MongoRepository<,>));
34+
3135
builder.Services.AddJsonApi(ConfigureJsonApiOptions, facade => facade.AddCurrentAssembly());
3236
builder.Services.AddJsonApiMongoDb();
3337

34-
builder.Services.AddScoped(typeof(IResourceReadRepository<,>), typeof(MongoRepository<,>));
35-
builder.Services.AddScoped(typeof(IResourceWriteRepository<,>), typeof(MongoRepository<,>));
36-
builder.Services.AddScoped(typeof(IResourceRepository<,>), typeof(MongoRepository<,>));
37-
3838
WebApplication app = builder.Build();
3939

4040
// Configure the HTTP request pipeline.

src/JsonApiDotNetCore.MongoDb/Configuration/ServiceCollectionExtensions.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using JsonApiDotNetCore.MongoDb.Repositories;
66
using JsonApiDotNetCore.Queries;
77
using Microsoft.Extensions.DependencyInjection;
8+
using Microsoft.Extensions.DependencyInjection.Extensions;
89

910
namespace JsonApiDotNetCore.MongoDb.Configuration;
1011

@@ -16,7 +17,9 @@ public static class ServiceCollectionExtensions
1617
[PublicAPI]
1718
public static IServiceCollection AddJsonApiMongoDb(this IServiceCollection services)
1819
{
19-
services.AddScoped<IMongoDataAccess, MongoDataAccess>();
20+
services.TryAddScoped<IMongoDataAccess, MongoDataAccess>();
21+
22+
// Replace the built-in implementations from JsonApiDotNetCore.
2023
services.AddScoped<IOperationsTransactionFactory, MongoTransactionFactory>();
2124
services.AddScoped<ISparseFieldSetCache, HideRelationshipsSparseFieldSetCache>();
2225

test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/AtomicOperationsFixture.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
using JetBrains.Annotations;
22
using JsonApiDotNetCore.Configuration;
33
using JsonApiDotNetCoreMongoDbTests.IntegrationTests.AtomicOperations.Meta;
4-
using Microsoft.Extensions.DependencyInjection;
4+
using Microsoft.Extensions.DependencyInjection.Extensions;
55
using TestBuildingBlocks;
66
using Xunit;
77

@@ -18,9 +18,9 @@ public AtomicOperationsFixture()
1818

1919
TestContext.UseController<OperationsController>();
2020

21-
TestContext.ConfigureServicesAfterStartup(services =>
21+
TestContext.ConfigureServices(services =>
2222
{
23-
services.AddSingleton<ResourceDefinitionHitCounter>();
23+
services.TryAddSingleton<ResourceDefinitionHitCounter>();
2424

2525
services.AddResourceDefinition<MusicTrackMetaDefinition>();
2626
services.AddResourceDefinition<TextLanguageMetaDefinition>();

test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Transactions/AtomicTransactionConsistencyTests.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
using FluentAssertions;
33
using JsonApiDotNetCore.Configuration;
44
using JsonApiDotNetCore.Serialization.Objects;
5-
using Microsoft.Extensions.DependencyInjection;
5+
using Microsoft.Extensions.DependencyInjection.Extensions;
66
using TestBuildingBlocks;
77
using Xunit;
88

@@ -21,9 +21,9 @@ public AtomicTransactionConsistencyTests(IntegrationTestContext<TestableStartup,
2121

2222
testContext.UseController<OperationsController>();
2323

24-
testContext.ConfigureServicesAfterStartup(services =>
24+
testContext.ConfigureServices(services =>
2525
{
26-
services.AddSingleton<ResourceDefinitionHitCounter>();
26+
services.TryAddSingleton<ResourceDefinitionHitCounter>();
2727

2828
services.AddResourceRepository<PerformerRepository>();
2929
services.AddResourceRepository<MusicTrackRepository>();

test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/Meta/ResourceMetaTests.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using JsonApiDotNetCore.Configuration;
44
using JsonApiDotNetCore.Serialization.Objects;
55
using Microsoft.Extensions.DependencyInjection;
6+
using Microsoft.Extensions.DependencyInjection.Extensions;
67
using TestBuildingBlocks;
78
using Xunit;
89

@@ -21,9 +22,9 @@ public ResourceMetaTests(IntegrationTestContext<TestableStartup, MetaDbContext>
2122

2223
testContext.UseController<SupportTicketsController>();
2324

24-
testContext.ConfigureServicesAfterStartup(services =>
25+
testContext.ConfigureServices(services =>
2526
{
26-
services.AddSingleton<ResourceDefinitionHitCounter>();
27+
services.TryAddSingleton<ResourceDefinitionHitCounter>();
2728
services.AddResourceDefinition<SupportTicketDefinition>();
2829
});
2930

test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/Meta/TopLevelCountTests.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using JsonApiDotNetCore.Resources;
55
using JsonApiDotNetCore.Serialization.Objects;
66
using Microsoft.Extensions.DependencyInjection;
7+
using Microsoft.Extensions.DependencyInjection.Extensions;
78
using TestBuildingBlocks;
89
using Xunit;
910

@@ -22,9 +23,9 @@ public TopLevelCountTests(IntegrationTestContext<TestableStartup, MetaDbContext>
2223

2324
testContext.UseController<SupportTicketsController>();
2425

25-
testContext.ConfigureServicesAfterStartup(services =>
26+
testContext.ConfigureServices(services =>
2627
{
27-
services.AddScoped(typeof(IResourceChangeTracker<>), typeof(NeverSameResourceChangeTracker<>));
28+
services.TryAddScoped(typeof(IResourceChangeTracker<>), typeof(NeverSameResourceChangeTracker<>));
2829
});
2930

3031
var options = (JsonApiOptions)testContext.Factory.Services.GetRequiredService<IJsonApiOptions>();

test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/QueryStrings/SparseFieldSets/SparseFieldSetTests.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using JsonApiDotNetCore.Configuration;
44
using JsonApiDotNetCore.Serialization.Objects;
55
using Microsoft.Extensions.DependencyInjection;
6+
using Microsoft.Extensions.DependencyInjection.Extensions;
67
using TestBuildingBlocks;
78
using Xunit;
89

@@ -23,9 +24,9 @@ public SparseFieldSetTests(IntegrationTestContext<TestableStartup, QueryStringDb
2324
testContext.UseController<WebAccountsController>();
2425
testContext.UseController<BlogsController>();
2526

26-
testContext.ConfigureServicesAfterStartup(services =>
27+
testContext.ConfigureServices(services =>
2728
{
28-
services.AddSingleton<ResourceCaptureStore>();
29+
services.TryAddSingleton<ResourceCaptureStore>();
2930

3031
services.AddResourceRepository<ResultCapturingRepository<Blog, string?>>();
3132
services.AddResourceRepository<ResultCapturingRepository<BlogPost, string?>>();

test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/Creating/CreateResourceWithClientGeneratedIdTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public CreateResourceWithClientGeneratedIdTests(IntegrationTestContext<TestableS
2222
testContext.UseController<WorkItemGroupsController>();
2323
testContext.UseController<RgbColorsController>();
2424

25-
testContext.ConfigureServicesAfterStartup(services =>
25+
testContext.ConfigureServices(services =>
2626
{
2727
services.AddResourceDefinition<ImplicitlyChangingWorkItemGroupDefinition>();
2828
});

test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/Updating/Resources/UpdateResourceTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public UpdateResourceTests(IntegrationTestContext<TestableStartup, ReadWriteDbCo
2323
testContext.UseController<UserAccountsController>();
2424
testContext.UseController<RgbColorsController>();
2525

26-
testContext.ConfigureServicesAfterStartup(services =>
26+
testContext.ConfigureServices(services =>
2727
{
2828
services.AddResourceDefinition<ImplicitlyChangingWorkItemDefinition>();
2929
services.AddResourceDefinition<ImplicitlyChangingWorkItemGroupDefinition>();

test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ResourceDefinitions/Reading/ResourceDefinitionReadTests.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using JsonApiDotNetCore.Configuration;
44
using JsonApiDotNetCore.Serialization.Objects;
55
using Microsoft.Extensions.DependencyInjection;
6+
using Microsoft.Extensions.DependencyInjection.Extensions;
67
using TestBuildingBlocks;
78
using Xunit;
89

@@ -23,10 +24,10 @@ public ResourceDefinitionReadTests(IntegrationTestContext<TestableStartup, Unive
2324
testContext.UseController<PlanetsController>();
2425
testContext.UseController<MoonsController>();
2526

26-
testContext.ConfigureServicesAfterStartup(services =>
27+
testContext.ConfigureServices(services =>
2728
{
28-
services.AddSingleton<IClientSettingsProvider, TestClientSettingsProvider>();
29-
services.AddSingleton<ResourceDefinitionHitCounter>();
29+
services.TryAddSingleton<IClientSettingsProvider, TestClientSettingsProvider>();
30+
services.TryAddSingleton<ResourceDefinitionHitCounter>();
3031

3132
services.AddResourceDefinition<MoonDefinition>();
3233
services.AddResourceDefinition<PlanetDefinition>();

test/TestBuildingBlocks/IntegrationTestContext.cs

Lines changed: 20 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
using Microsoft.AspNetCore.Mvc.Testing;
1212
using Microsoft.AspNetCore.TestHost;
1313
using Microsoft.Extensions.DependencyInjection;
14+
using Microsoft.Extensions.DependencyInjection.Extensions;
1415
using Microsoft.Extensions.Hosting;
1516
using MongoDB.Driver;
1617

@@ -36,8 +37,7 @@ public class IntegrationTestContext<TStartup, TMongoDbContextShim> : Integration
3637
private readonly Lazy<WebApplicationFactory<TStartup>> _lazyFactory;
3738
private readonly HashSet<Type> _resourceClrTypes = new();
3839
private readonly TestControllerProvider _testControllerProvider = new();
39-
40-
private Action<IServiceCollection>? _afterServicesConfiguration;
40+
private Action<IServiceCollection>? _configureServices;
4141

4242
protected override JsonSerializerOptions SerializerOptions
4343
{
@@ -86,16 +86,24 @@ private WebApplicationFactory<TStartup> CreateFactory()
8686
{
8787
var factory = new IntegrationTestWebApplicationFactory();
8888

89-
factory.ConfigureServicesBeforeStartup(services =>
89+
factory.ConfigureServices(services =>
9090
{
91+
_configureServices?.Invoke(services);
92+
9193
services.ReplaceControllers(_testControllerProvider);
9294

93-
services.AddSingleton(_ =>
95+
services.TryAddSingleton(_ =>
9496
{
9597
var client = new MongoClient(_runner.Value.ConnectionString);
96-
return client.GetDatabase($"JsonApiDotNetCore_MongoDb_{new Random().Next()}_Test");
98+
return client.GetDatabase($"JsonApiDotNetCore_MongoDb_{Random.Shared.Next()}_Test");
9799
});
98100

101+
services.TryAddScoped<TMongoDbContextShim>();
102+
103+
services.TryAddScoped(typeof(IResourceReadRepository<,>), typeof(MongoRepository<,>));
104+
services.TryAddScoped(typeof(IResourceWriteRepository<,>), typeof(MongoRepository<,>));
105+
services.TryAddScoped(typeof(IResourceRepository<,>), typeof(MongoRepository<,>));
106+
99107
services.AddJsonApi(ConfigureJsonApiOptions, resources: builder =>
100108
{
101109
foreach (Type resourceClrType in _resourceClrTypes)
@@ -105,16 +113,8 @@ private WebApplicationFactory<TStartup> CreateFactory()
105113
});
106114

107115
services.AddJsonApiMongoDb();
108-
109-
services.AddScoped(typeof(IResourceReadRepository<,>), typeof(MongoRepository<,>));
110-
services.AddScoped(typeof(IResourceWriteRepository<,>), typeof(MongoRepository<,>));
111-
services.AddScoped(typeof(IResourceRepository<,>), typeof(MongoRepository<,>));
112-
113-
services.AddScoped<TMongoDbContextShim>();
114116
});
115117

116-
factory.ConfigureServicesAfterStartup(_afterServicesConfiguration);
117-
118118
// We have placed an appsettings.json in the TestBuildingBlock project folder and set the content root to there. Note that controllers
119119
// are not discovered in the content root but are registered manually using IntegrationTestContext.UseController.
120120
return factory.WithWebHostBuilder(builder => builder.UseSolutionRelativeContentRoot($"test/{nameof(TestBuildingBlocks)}"));
@@ -127,9 +127,9 @@ private void ConfigureJsonApiOptions(JsonApiOptions options)
127127
options.SerializerOptions.WriteIndented = true;
128128
}
129129

130-
public void ConfigureServicesAfterStartup(Action<IServiceCollection> servicesConfiguration)
130+
public void ConfigureServices(Action<IServiceCollection> configureServices)
131131
{
132-
_afterServicesConfiguration = servicesConfiguration;
132+
_configureServices = configureServices;
133133
}
134134

135135
public async Task RunOnDatabaseAsync(Func<TMongoDbContextShim, Task> asyncAction)
@@ -162,17 +162,11 @@ public override async Task DisposeAsync()
162162

163163
private sealed class IntegrationTestWebApplicationFactory : WebApplicationFactory<TStartup>
164164
{
165-
private Action<IServiceCollection>? _beforeServicesConfiguration;
166-
private Action<IServiceCollection>? _afterServicesConfiguration;
167-
168-
public void ConfigureServicesBeforeStartup(Action<IServiceCollection>? servicesConfiguration)
169-
{
170-
_beforeServicesConfiguration = servicesConfiguration;
171-
}
165+
private Action<IServiceCollection>? _configureServices;
172166

173-
public void ConfigureServicesAfterStartup(Action<IServiceCollection>? servicesConfiguration)
167+
public void ConfigureServices(Action<IServiceCollection>? configureServices)
174168
{
175-
_afterServicesConfiguration = servicesConfiguration;
169+
_configureServices = configureServices;
176170
}
177171

178172
protected override IHostBuilder CreateHostBuilder()
@@ -184,21 +178,12 @@ protected override IHostBuilder CreateHostBuilder()
184178
.CreateDefaultBuilder(null)
185179
.ConfigureWebHostDefaults(webBuilder =>
186180
{
187-
webBuilder.ConfigureServices(services =>
188-
{
189-
_beforeServicesConfiguration?.Invoke(services);
190-
});
191-
181+
webBuilder.ConfigureServices(services => _configureServices?.Invoke(services));
192182
webBuilder.UseStartup<TStartup>();
193-
194-
webBuilder.ConfigureServices(services =>
195-
{
196-
_afterServicesConfiguration?.Invoke(services);
197-
});
198183
});
199184

200-
// @formatter:keep_existing_linebreaks restore
201185
// @formatter:wrap_before_first_method_call restore
186+
// @formatter:wrap_chained_method_calls restore
202187
}
203188
}
204189
}

0 commit comments

Comments
 (0)