Skip to content

Commit 215d664

Browse files
author
Bart Koelman
committed
Simpler registration for resource definitions
1 parent acc5d90 commit 215d664

File tree

9 files changed

+204
-20
lines changed

9 files changed

+204
-20
lines changed

src/JsonApiDotNetCore/Configuration/ServiceCollectionExtensions.cs

+14
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using JetBrains.Annotations;
66
using JsonApiDotNetCore.Errors;
77
using JsonApiDotNetCore.Repositories;
8+
using JsonApiDotNetCore.Resources;
89
using JsonApiDotNetCore.Serialization.Building;
910
using JsonApiDotNetCore.Serialization.Client.Internal;
1011
using JsonApiDotNetCore.Services;
@@ -101,6 +102,19 @@ public static IServiceCollection AddResourceRepository<TRepository>(this IServic
101102
return services;
102103
}
103104

105+
/// <summary>
106+
/// Adds IoC container registrations for the various JsonApiDotNetCore resource definition interfaces, such as
107+
/// <see cref="IResourceDefinition{TResource}" /> and <see cref="IResourceDefinition{TResource,TId}" />.
108+
/// </summary>
109+
public static IServiceCollection AddResourceDefinition<TResourceDefinition>(this IServiceCollection services)
110+
{
111+
ArgumentGuard.NotNull(services, nameof(services));
112+
113+
RegisterForConstructedType(services, typeof(TResourceDefinition), ServiceDiscoveryFacade.ResourceDefinitionInterfaces);
114+
115+
return services;
116+
}
117+
104118
private static void RegisterForConstructedType(IServiceCollection services, Type implementationType, IEnumerable<Type> openGenericInterfaces)
105119
{
106120
bool seenCompatibleInterface = false;

test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/Meta/AtomicResourceMetaTests.cs

+3-5
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
1-
using System;
21
using System.Net;
32
using System.Net.Http;
43
using System.Threading.Tasks;
54
using FluentAssertions;
65
using FluentAssertions.Extensions;
7-
using JsonApiDotNetCore.Resources;
6+
using JsonApiDotNetCore.Configuration;
87
using JsonApiDotNetCore.Serialization.Objects;
98
using JsonApiDotNetCoreExample.Controllers;
109
using JsonApiDotNetCoreExampleTests.Startups;
11-
using Microsoft.Extensions.DependencyInjection;
1210
using TestBuildingBlocks;
1311
using Xunit;
1412

@@ -27,8 +25,8 @@ public AtomicResourceMetaTests(ExampleIntegrationTestContext<TestableStartup<Ope
2725

2826
testContext.ConfigureServicesAfterStartup(services =>
2927
{
30-
services.AddScoped<IResourceDefinition<MusicTrack, Guid>, MusicTrackMetaDefinition>();
31-
services.AddScoped<IResourceDefinition<TextLanguage, Guid>, TextLanguageMetaDefinition>();
28+
services.AddResourceDefinition<MusicTrackMetaDefinition>();
29+
services.AddResourceDefinition<TextLanguageMetaDefinition>();
3230
});
3331
}
3432

test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/QueryStrings/AtomicQueryStringTests.cs

+1-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
using FluentAssertions;
77
using FluentAssertions.Extensions;
88
using JsonApiDotNetCore.Configuration;
9-
using JsonApiDotNetCore.Resources;
109
using JsonApiDotNetCore.Serialization.Objects;
1110
using JsonApiDotNetCoreExample.Controllers;
1211
using JsonApiDotNetCoreExampleTests.Startups;
@@ -38,7 +37,7 @@ public AtomicQueryStringTests(ExampleIntegrationTestContext<TestableStartup<Oper
3837
UtcNow = FrozenTime
3938
});
4039

41-
services.AddScoped<IResourceDefinition<MusicTrack, Guid>, MusicTrackReleaseDefinition>();
40+
services.AddResourceDefinition<MusicTrackReleaseDefinition>();
4241
});
4342

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

test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/ResourceDefinitions/AtomicSparseFieldSetResourceDefinitionTests.cs

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Net.Http;
44
using System.Threading.Tasks;
55
using FluentAssertions;
6+
using JsonApiDotNetCore.Configuration;
67
using JsonApiDotNetCore.Resources;
78
using JsonApiDotNetCore.Serialization.Objects;
89
using JsonApiDotNetCoreExample.Controllers;
@@ -28,7 +29,7 @@ public AtomicSparseFieldSetResourceDefinitionTests(ExampleIntegrationTestContext
2829
testContext.ConfigureServicesAfterStartup(services =>
2930
{
3031
services.AddSingleton<LyricPermissionProvider>();
31-
services.AddScoped<IResourceDefinition<Lyric, long>, LyricTextDefinition>();
32+
services.AddResourceDefinition<LyricTextDefinition>();
3233
services.AddScoped(typeof(IResourceChangeTracker<>), typeof(NeverSameResourceChangeTracker<>));
3334
});
3435
}

test/JsonApiDotNetCoreExampleTests/IntegrationTests/EagerLoading/EagerLoadingTests.cs

+2-3
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,10 @@
22
using System.Net.Http;
33
using System.Threading.Tasks;
44
using FluentAssertions;
5-
using JsonApiDotNetCore.Resources;
5+
using JsonApiDotNetCore.Configuration;
66
using JsonApiDotNetCore.Serialization.Objects;
77
using JsonApiDotNetCoreExampleTests.Startups;
88
using Microsoft.EntityFrameworkCore;
9-
using Microsoft.Extensions.DependencyInjection;
109
using TestBuildingBlocks;
1110
using Xunit;
1211

@@ -27,7 +26,7 @@ public EagerLoadingTests(ExampleIntegrationTestContext<TestableStartup<EagerLoad
2726

2827
testContext.ConfigureServicesAfterStartup(services =>
2928
{
30-
services.AddScoped<IResourceDefinition<Building>, BuildingResourceDefinition>();
29+
services.AddResourceDefinition<BuildingResourceDefinition>();
3130
});
3231
}
3332

test/JsonApiDotNetCoreExampleTests/IntegrationTests/Meta/ResourceMetaTests.cs

+2-3
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,9 @@
33
using System.Net.Http;
44
using System.Threading.Tasks;
55
using FluentAssertions;
6-
using JsonApiDotNetCore.Resources;
6+
using JsonApiDotNetCore.Configuration;
77
using JsonApiDotNetCore.Serialization.Objects;
88
using JsonApiDotNetCoreExampleTests.Startups;
9-
using Microsoft.Extensions.DependencyInjection;
109
using TestBuildingBlocks;
1110
using Xunit;
1211

@@ -26,7 +25,7 @@ public ResourceMetaTests(ExampleIntegrationTestContext<TestableStartup<SupportDb
2625

2726
testContext.ConfigureServicesAfterStartup(services =>
2827
{
29-
services.AddScoped<IResourceDefinition<SupportTicket>, SupportTicketDefinition>();
28+
services.AddResourceDefinition<SupportTicketDefinition>();
3029
});
3130
}
3231

test/JsonApiDotNetCoreExampleTests/IntegrationTests/ResourceDefinitions/ResourceDefinitionQueryCallbackTests.cs

+1-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
using FluentAssertions;
66
using FluentAssertions.Extensions;
77
using JsonApiDotNetCore.Configuration;
8-
using JsonApiDotNetCore.Resources;
98
using JsonApiDotNetCore.Serialization.Objects;
109
using JsonApiDotNetCoreExampleTests.Startups;
1110
using Microsoft.Extensions.DependencyInjection;
@@ -27,7 +26,7 @@ public ResourceDefinitionQueryCallbackTests(ExampleIntegrationTestContext<Testab
2726

2827
testContext.ConfigureServicesAfterStartup(services =>
2928
{
30-
services.AddScoped<IResourceDefinition<CallableResource>, CallableResourceDefinition>();
29+
services.AddResourceDefinition<CallableResourceDefinition>();
3130
services.AddSingleton<IUserRolesService, FakeUserRolesService>();
3231
});
3332

test/JsonApiDotNetCoreExampleTests/IntegrationTests/SoftDeletion/SoftDeletionTests.cs

+3-4
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,9 @@
44
using System.Net.Http;
55
using System.Threading.Tasks;
66
using FluentAssertions;
7-
using JsonApiDotNetCore.Resources;
7+
using JsonApiDotNetCore.Configuration;
88
using JsonApiDotNetCore.Serialization.Objects;
99
using JsonApiDotNetCoreExampleTests.Startups;
10-
using Microsoft.Extensions.DependencyInjection;
1110
using TestBuildingBlocks;
1211
using Xunit;
1312

@@ -26,8 +25,8 @@ public SoftDeletionTests(ExampleIntegrationTestContext<TestableStartup<SoftDelet
2625

2726
testContext.ConfigureServicesAfterStartup(services =>
2827
{
29-
services.AddScoped<IResourceDefinition<Company>, SoftDeletionResourceDefinition<Company>>();
30-
services.AddScoped<IResourceDefinition<Department>, SoftDeletionResourceDefinition<Department>>();
28+
services.AddResourceDefinition<SoftDeletionResourceDefinition<Company>>();
29+
services.AddResourceDefinition<SoftDeletionResourceDefinition<Department>>();
3130
});
3231
}
3332

test/UnitTests/Extensions/ServiceCollectionExtensionsTests.cs

+176
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,34 @@ public void AddResourceRepository_Registers_All_LongForm_Repository_Interfaces()
170170
Assert.IsType<GuidResourceRepository>(provider.GetRequiredService(typeof(IResourceWriteRepository<GuidResource, Guid>)));
171171
}
172172

173+
[Fact]
174+
public void AddResourceDefinition_Registers_Shorthand_Definition_Interface()
175+
{
176+
// Arrange
177+
var services = new ServiceCollection();
178+
179+
// Act
180+
services.AddResourceDefinition<IntResourceDefinition>();
181+
182+
// Assert
183+
ServiceProvider provider = services.BuildServiceProvider();
184+
Assert.IsType<IntResourceDefinition>(provider.GetRequiredService(typeof(IResourceDefinition<IntResource>)));
185+
}
186+
187+
[Fact]
188+
public void AddResourceDefinition_Registers_LongForm_Definition_Interface()
189+
{
190+
// Arrange
191+
var services = new ServiceCollection();
192+
193+
// Act
194+
services.AddResourceDefinition<GuidResourceDefinition>();
195+
196+
// Assert
197+
ServiceProvider provider = services.BuildServiceProvider();
198+
Assert.IsType<GuidResourceDefinition>(provider.GetRequiredService(typeof(IResourceDefinition<GuidResource, Guid>)));
199+
}
200+
173201
[Fact]
174202
public void AddJsonApi_With_Context_Uses_Resource_Type_Name_If_NoOtherSpecified()
175203
{
@@ -421,6 +449,154 @@ public Task RemoveFromToManyRelationshipAsync(GuidResource primaryResource, ISet
421449
}
422450
}
423451

452+
[UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)]
453+
private sealed class IntResourceDefinition : IResourceDefinition<IntResource>
454+
{
455+
public IReadOnlyCollection<IncludeElementExpression> OnApplyIncludes(IReadOnlyCollection<IncludeElementExpression> existingIncludes)
456+
{
457+
throw new NotImplementedException();
458+
}
459+
460+
public FilterExpression OnApplyFilter(FilterExpression existingFilter)
461+
{
462+
throw new NotImplementedException();
463+
}
464+
465+
public SortExpression OnApplySort(SortExpression existingSort)
466+
{
467+
throw new NotImplementedException();
468+
}
469+
470+
public PaginationExpression OnApplyPagination(PaginationExpression existingPagination)
471+
{
472+
throw new NotImplementedException();
473+
}
474+
475+
public SparseFieldSetExpression OnApplySparseFieldSet(SparseFieldSetExpression existingSparseFieldSet)
476+
{
477+
throw new NotImplementedException();
478+
}
479+
480+
public QueryStringParameterHandlers<IntResource> OnRegisterQueryableHandlersForQueryStringParameters()
481+
{
482+
throw new NotImplementedException();
483+
}
484+
485+
public IDictionary<string, object> GetMeta(IntResource resource)
486+
{
487+
throw new NotImplementedException();
488+
}
489+
490+
public Task OnInitializeResourceAsync(IntResource resource, CancellationToken cancellationToken)
491+
{
492+
throw new NotImplementedException();
493+
}
494+
495+
public Task OnBeforeCreateResourceAsync(IntResource resource, CancellationToken cancellationToken)
496+
{
497+
throw new NotImplementedException();
498+
}
499+
500+
public Task OnAfterCreateResourceAsync(IntResource resource, CancellationToken cancellationToken)
501+
{
502+
throw new NotImplementedException();
503+
}
504+
505+
public Task OnBeforeUpdateResourceAsync(IntResource resource, CancellationToken cancellationToken)
506+
{
507+
throw new NotImplementedException();
508+
}
509+
510+
public Task OnAfterUpdateResourceAsync(IntResource resource, CancellationToken cancellationToken)
511+
{
512+
throw new NotImplementedException();
513+
}
514+
515+
public Task OnBeforeDeleteResourceAsync(int id, CancellationToken cancellationToken)
516+
{
517+
throw new NotImplementedException();
518+
}
519+
520+
public Task OnAfterDeleteResourceAsync(int id, CancellationToken cancellationToken)
521+
{
522+
throw new NotImplementedException();
523+
}
524+
}
525+
526+
[UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)]
527+
private sealed class GuidResourceDefinition : IResourceDefinition<GuidResource, Guid>
528+
{
529+
public IReadOnlyCollection<IncludeElementExpression> OnApplyIncludes(IReadOnlyCollection<IncludeElementExpression> existingIncludes)
530+
{
531+
throw new NotImplementedException();
532+
}
533+
534+
public FilterExpression OnApplyFilter(FilterExpression existingFilter)
535+
{
536+
throw new NotImplementedException();
537+
}
538+
539+
public SortExpression OnApplySort(SortExpression existingSort)
540+
{
541+
throw new NotImplementedException();
542+
}
543+
544+
public PaginationExpression OnApplyPagination(PaginationExpression existingPagination)
545+
{
546+
throw new NotImplementedException();
547+
}
548+
549+
public SparseFieldSetExpression OnApplySparseFieldSet(SparseFieldSetExpression existingSparseFieldSet)
550+
{
551+
throw new NotImplementedException();
552+
}
553+
554+
public QueryStringParameterHandlers<GuidResource> OnRegisterQueryableHandlersForQueryStringParameters()
555+
{
556+
throw new NotImplementedException();
557+
}
558+
559+
public IDictionary<string, object> GetMeta(GuidResource resource)
560+
{
561+
throw new NotImplementedException();
562+
}
563+
564+
public Task OnInitializeResourceAsync(GuidResource resource, CancellationToken cancellationToken)
565+
{
566+
throw new NotImplementedException();
567+
}
568+
569+
public Task OnBeforeCreateResourceAsync(GuidResource resource, CancellationToken cancellationToken)
570+
{
571+
throw new NotImplementedException();
572+
}
573+
574+
public Task OnAfterCreateResourceAsync(GuidResource resource, CancellationToken cancellationToken)
575+
{
576+
throw new NotImplementedException();
577+
}
578+
579+
public Task OnBeforeUpdateResourceAsync(GuidResource resource, CancellationToken cancellationToken)
580+
{
581+
throw new NotImplementedException();
582+
}
583+
584+
public Task OnAfterUpdateResourceAsync(GuidResource resource, CancellationToken cancellationToken)
585+
{
586+
throw new NotImplementedException();
587+
}
588+
589+
public Task OnBeforeDeleteResourceAsync(Guid id, CancellationToken cancellationToken)
590+
{
591+
throw new NotImplementedException();
592+
}
593+
594+
public Task OnAfterDeleteResourceAsync(Guid id, CancellationToken cancellationToken)
595+
{
596+
throw new NotImplementedException();
597+
}
598+
}
599+
424600
[UsedImplicitly(ImplicitUseTargetFlags.Members)]
425601
private sealed class TestContext : DbContext
426602
{

0 commit comments

Comments
 (0)