Skip to content

Commit 0b788b5

Browse files
committed
feat: remove intermediate service providers, consistent middleware component registration
1 parent de23e9f commit 0b788b5

24 files changed

+128
-244
lines changed

benchmarks/DependencyFactory.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ internal static class DependencyFactory
1313
{
1414
public static IResourceGraph CreateResourceGraph(IJsonApiOptions options)
1515
{
16-
IResourceGraphBuilder builder = new ResourceGraphBuilder(options, NullLoggerFactory.Instance);
16+
ResourceGraphBuilder builder = new ResourceGraphBuilder(options, NullLoggerFactory.Instance);
1717
builder.AddResource<BenchmarkResource>(BenchmarkResourcePublicNames.Type);
1818
return builder.Build();
1919
}

src/Examples/JsonApiDotNetCoreExample/Startups/EmptyStartup.cs

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using Microsoft.AspNetCore.Hosting;
33
using Microsoft.Extensions.Configuration;
44
using Microsoft.Extensions.DependencyInjection;
5+
using Microsoft.Extensions.Logging;
56

67
namespace JsonApiDotNetCoreExample
78
{
@@ -11,16 +12,10 @@ namespace JsonApiDotNetCoreExample
1112
/// </summary>
1213
public abstract class EmptyStartup
1314
{
14-
protected EmptyStartup(IConfiguration configuration)
15-
{
16-
}
15+
protected EmptyStartup(IConfiguration configuration) { }
1716

18-
public virtual void ConfigureServices(IServiceCollection services)
19-
{
20-
}
17+
public virtual void ConfigureServices(IServiceCollection services) { }
2118

22-
public virtual void Configure(IApplicationBuilder app, IWebHostEnvironment environment)
23-
{
24-
}
19+
public virtual void Configure(IApplicationBuilder app, IWebHostEnvironment environment) { }
2520
}
2621
}

src/Examples/JsonApiDotNetCoreExample/Startups/Startup.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
using JsonApiDotNetCore.QueryStrings;
1111
using JsonApiDotNetCoreExample.Services;
1212
using Microsoft.AspNetCore.Authentication;
13+
using Microsoft.Extensions.Logging;
1314
using Newtonsoft.Json;
1415
using Newtonsoft.Json.Converters;
1516

@@ -28,7 +29,6 @@ public Startup(IConfiguration configuration) : base(configuration)
2829
public override void ConfigureServices(IServiceCollection services)
2930
{
3031
ConfigureClock(services);
31-
3232
services.AddScoped<SkipCacheQueryStringParameterReader>();
3333
services.AddScoped<IQueryStringParameterReader>(sp => sp.GetService<SkipCacheQueryStringParameterReader>());
3434

src/Examples/JsonApiDotNetCoreExample/Startups/TestStartup.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,13 @@
22
using Microsoft.AspNetCore.Authentication;
33
using Microsoft.Extensions.Configuration;
44
using Microsoft.Extensions.DependencyInjection;
5+
using Microsoft.Extensions.Logging;
56

67
namespace JsonApiDotNetCoreExample
78
{
89
public class TestStartup : Startup
910
{
10-
public TestStartup(IConfiguration configuration) : base(configuration)
11-
{
12-
}
11+
public TestStartup(IConfiguration configuration) : base(configuration) { }
1312

1413
protected override void ConfigureClock(IServiceCollection services)
1514
{

src/JsonApiDotNetCore/Builders/IResourceGraphBuilder.cs

Lines changed: 0 additions & 44 deletions
This file was deleted.

src/JsonApiDotNetCore/Builders/JsonApiApplicationBuilder.cs

Lines changed: 46 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
using JsonApiDotNetCore.RequestServices.Contracts;
2727
using JsonApiDotNetCore.Services.Contract;
2828
using Microsoft.AspNetCore.Mvc;
29+
using Microsoft.Extensions.Logging;
2930

3031
namespace JsonApiDotNetCore.Builders
3132
{
@@ -37,17 +38,20 @@ internal sealed class JsonApiApplicationBuilder : IJsonApiApplicationBuilder
3738
{
3839
private readonly JsonApiOptions _options = new JsonApiOptions();
3940
private readonly IServiceCollection _services;
40-
private IServiceDiscoveryFacade _serviceDiscoveryFacade;
41-
private IResourceGraphBuilder _resourceGraphBuilder;
4241
private readonly IMvcCoreBuilder _mvcBuilder;
43-
private ServiceProvider _intermediateServiceProvider;
42+
private readonly ResourceGraphBuilder _resourceGraphBuilder;
43+
private readonly ServiceDiscoveryFacade _serviceDiscoveryFacade;
44+
private readonly ServiceProvider _intermediateProvider;
4445
public Action<MvcOptions> ConfigureMvcOptions { get; set; }
4546

46-
public JsonApiApplicationBuilder(IServiceCollection services,
47-
IMvcCoreBuilder mvcBuilder)
47+
public JsonApiApplicationBuilder(IServiceCollection services, IMvcCoreBuilder mvcBuilder)
4848
{
4949
_services = services;
5050
_mvcBuilder = mvcBuilder;
51+
_intermediateProvider = services.BuildServiceProvider();
52+
var loggerFactory = _intermediateProvider.GetService<ILoggerFactory>();
53+
_resourceGraphBuilder = new ResourceGraphBuilder(_options, loggerFactory);
54+
_serviceDiscoveryFacade = new ServiceDiscoveryFacade(_services, _resourceGraphBuilder, loggerFactory);
5155
}
5256

5357
/// <summary>
@@ -57,43 +61,30 @@ public void ConfigureJsonApiOptions(Action<JsonApiOptions> configureOptions)
5761
{
5862
configureOptions?.Invoke(_options);
5963
}
60-
61-
/// <summary>
62-
/// Registers services that are required for the configuration of JsonApiDotNetCore during the start up.
63-
/// </summary>
64-
public void RegisterJsonApiStartupServices()
65-
{
66-
_services.AddSingleton<IJsonApiOptions>(_options);
67-
_services.TryAddSingleton<IJsonApiRoutingConvention, JsonApiRoutingConvention>();
68-
_services.TryAddSingleton<IResourceGraphBuilder, ResourceGraphBuilder>();
69-
_services.TryAddSingleton<IServiceDiscoveryFacade>(sp =>
70-
new ServiceDiscoveryFacade(_services, sp.GetRequiredService<IResourceGraphBuilder>()));
71-
}
72-
73-
public void ConfigureAutoDiscovery(Action<IServiceDiscoveryFacade> configureAutoDiscovery)
64+
65+
public void ConfigureAutoDiscovery(Action<ServiceDiscoveryFacade> configureAutoDiscovery)
7466
{
75-
var intermediateProvider = _services.BuildServiceProvider();
76-
_serviceDiscoveryFacade = intermediateProvider.GetRequiredService<IServiceDiscoveryFacade>();
77-
_resourceGraphBuilder = intermediateProvider.GetRequiredService<IResourceGraphBuilder>();
78-
RegisterDiscoverableAssemblies(configureAutoDiscovery, _serviceDiscoveryFacade);
79-
_intermediateServiceProvider = intermediateProvider;
67+
configureAutoDiscovery?.Invoke(_serviceDiscoveryFacade);
8068
}
8169

8270
/// <summary>
8371
/// Configures and build the resource graph with resources from the provided sources and adds it to the DI container.
8472
/// </summary>
85-
public void AddResourceGraph(Type dbContextType, Action<IResourceGraphBuilder> configureResources)
73+
public void AddResourceGraph(Type dbContextType, Action<ResourceGraphBuilder> configureResources)
8674
{
8775
AutoDiscoverResources(_serviceDiscoveryFacade);
88-
AddResourcesFromDbContext(dbContextType, _intermediateServiceProvider, _resourceGraphBuilder);
76+
if (dbContextType != null)
77+
{
78+
AddResourcesFromDbContext((DbContext)_intermediateProvider.GetService(dbContextType), _resourceGraphBuilder);
79+
}
8980
UserConfigureResources(configureResources, _resourceGraphBuilder);
9081
_services.AddSingleton(_resourceGraphBuilder.Build());
9182
}
9283

9384
/// <summary>
9485
/// Configures built-in .NET Core MVC (things like middleware, routing). Most of this configuration can be adjusted for the developers' need.
9586
/// Before calling .AddJsonApi(), a developer can register their own implementation of the following services to customize startup:
96-
/// <see cref="IResourceGraphBuilder"/>, <see cref="IServiceDiscoveryFacade"/>, <see cref="IJsonApiTypeMatchFilter"/>,
87+
/// <see cref="ResourceGraphBuilder"/>, <see cref="ServiceDiscoveryFacade"/>, <see cref="IJsonApiTypeMatchFilter"/>,
9788
/// <see cref="IJsonApiExceptionFilter"/> and <see cref="IJsonApiRoutingConvention"/>.
9889
/// </summary>
9990
public void ConfigureMvc()
@@ -104,9 +95,7 @@ public void ConfigureMvc()
10495
options.Filters.AddService<IJsonApiExceptionFilter>();
10596
options.Filters.AddService<IJsonApiTypeMatchFilter>();
10697
options.Filters.AddService<IQueryStringActionFilter>();
107-
options.Filters.Add(new ConvertEmptyActionResultFilter());
108-
options.InputFormatters.Insert(0, new JsonApiInputFormatter());
109-
options.OutputFormatters.Insert(0, new JsonApiOutputFormatter());
98+
options.Filters.AddService<IConvertEmptyActionResultFilter>();
11099
ConfigureMvcOptions?.Invoke(options);
111100
});
112101

@@ -122,7 +111,7 @@ public void ConfigureMvc()
122111
public void DiscoverInjectables()
123112
{
124113
_serviceDiscoveryFacade.DiscoverInjectables();
125-
_intermediateServiceProvider.Dispose();
114+
_intermediateProvider.Dispose();
126115
}
127116

128117
/// <summary>
@@ -143,27 +132,14 @@ public void ConfigureServices(Type dbContextType)
143132

144133
AddRepositoryLayer();
145134
AddServiceLayer();
135+
AddMiddlewareLayer();
146136

147-
_services.AddSingleton<IJsonApiApplicationBuilder>(this);
148-
_services.AddSingleton<IControllerResourceMapping>(sp => sp.GetService<IJsonApiRoutingConvention>());
149-
150-
_services.TryAddSingleton<IExceptionHandler, ExceptionHandler>();
151-
_services.TryAddScoped<IJsonApiExceptionFilter, JsonApiExceptionFilter>();
152-
_services.TryAddScoped<IJsonApiTypeMatchFilter, JsonApiTypeMatchFilter>();
153-
_services.TryAddScoped<IQueryStringActionFilter, QueryStringActionFilter>();
154-
155-
_services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
156137
_services.AddSingleton<IResourceContextProvider>(sp => sp.GetRequiredService<IResourceGraph>());
157138

158-
_services.AddScoped<ICurrentRequest, CurrentRequest>();
159139
_services.AddScoped<IScopedServiceProvider, RequestScopedServiceProvider>();
160-
_services.AddScoped<IJsonApiWriter, JsonApiWriter>();
161-
_services.AddScoped<IJsonApiReader, JsonApiReader>();
162140
_services.AddScoped<IGenericServiceFactory, GenericServiceFactory>();
163141
_services.AddScoped(typeof(RepositoryRelationshipUpdateHelper<>));
164-
_services.AddScoped<ITargetedFields, TargetedFields>();
165142
_services.AddScoped<IResourceDefinitionProvider, ResourceDefinitionProvider>();
166-
_services.AddScoped<IFieldsToSerialize, FieldsToSerialize>();
167143
_services.AddScoped(typeof(IResourceChangeTracker<>), typeof(ResourceChangeTracker<>));
168144
_services.AddScoped<IResourceFactory, ResourceFactory>();
169145
_services.AddScoped<IPaginationContext, PaginationContext>();
@@ -179,10 +155,25 @@ public void ConfigureServices(Type dbContextType)
179155
_services.AddScoped<IInverseRelationships, InverseRelationships>();
180156
}
181157

182-
private void RegisterDiscoverableAssemblies(Action<IServiceDiscoveryFacade> configureAutoDiscovery,
183-
IServiceDiscoveryFacade serviceDiscoveryFacade)
158+
private void AddMiddlewareLayer()
184159
{
185-
configureAutoDiscovery?.Invoke(serviceDiscoveryFacade);
160+
_services.AddSingleton<IJsonApiOptions>(_options);
161+
_services.AddSingleton<IJsonApiApplicationBuilder>(this);
162+
_services.TryAddSingleton<IExceptionHandler, ExceptionHandler>();
163+
_services.TryAddScoped<IJsonApiExceptionFilter, JsonApiExceptionFilter>();
164+
_services.TryAddScoped<IJsonApiTypeMatchFilter, JsonApiTypeMatchFilter>();
165+
_services.TryAddScoped<IQueryStringActionFilter, QueryStringActionFilter>();
166+
_services.TryAddScoped<IConvertEmptyActionResultFilter, ConvertEmptyActionResultFilter>();
167+
_services.TryAddSingleton<IJsonApiInputFormatter, JsonApiInputFormatter>();
168+
_services.TryAddSingleton<IJsonApiOutputFormatter, JsonApiOutputFormatter>();
169+
_services.TryAddSingleton<IJsonApiRoutingConvention, JsonApiRoutingConvention>();
170+
_services.AddSingleton<IControllerResourceMapping>(sp => sp.GetService<IJsonApiRoutingConvention>());
171+
_services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
172+
_services.AddScoped<ICurrentRequest, CurrentRequest>();
173+
_services.AddScoped<IJsonApiWriter, JsonApiWriter>();
174+
_services.AddScoped<IJsonApiReader, JsonApiReader>();
175+
_services.AddScoped<ITargetedFields, TargetedFields>();
176+
_services.AddScoped<IFieldsToSerialize, FieldsToSerialize>();
186177
}
187178

188179
private void AddRepositoryLayer()
@@ -284,33 +275,27 @@ private void AddServerSerialization()
284275
_services.AddScoped<IResourceObjectBuilder, ResponseResourceObjectBuilder>();
285276
}
286277

287-
private void AddResourcesFromDbContext(Type dbContextType, ServiceProvider intermediateProvider,
288-
IResourceGraphBuilder builder)
278+
private void AddResourcesFromDbContext(DbContext dbContext, ResourceGraphBuilder builder)
289279
{
290-
if (dbContextType != null)
280+
foreach (var entityType in dbContext.Model.GetEntityTypes())
291281
{
292-
var dbContext = (DbContext) intermediateProvider.GetRequiredService(dbContextType);
293-
294-
foreach (var entityType in dbContext.Model.GetEntityTypes())
295-
{
296-
builder.AddResource(entityType.ClrType);
297-
}
282+
builder.AddResource(entityType.ClrType);
298283
}
299284
}
300285

301286
/// <summary>
302287
/// Performs auto-discovery of JsonApiDotNetCore services.
303288
/// </summary>
304-
private void AutoDiscoverResources(IServiceDiscoveryFacade serviceDiscoveryFacade)
289+
private void AutoDiscoverResources(ServiceDiscoveryFacade serviceDiscoveryFacade)
305290
{
306291
serviceDiscoveryFacade.DiscoverResources();
307292
}
308293

309294
/// <summary>
310-
/// Executes the action provided by the user to configure the resources using <see cref="IResourceGraphBuilder"/>
295+
/// Executes the action provided by the user to configure the resources using <see cref="ResourceGraphBuilder"/>
311296
/// </summary>
312-
private void UserConfigureResources(Action<IResourceGraphBuilder> configureResources,
313-
IResourceGraphBuilder resourceGraphBuilder)
297+
private void UserConfigureResources(Action<ResourceGraphBuilder> configureResources,
298+
ResourceGraphBuilder resourceGraphBuilder)
314299
{
315300
configureResources?.Invoke(resourceGraphBuilder);
316301
}

src/JsonApiDotNetCore/Builders/ResourceGraphBuilder.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
namespace JsonApiDotNetCore.Builders
1515
{
16-
public class ResourceGraphBuilder : IResourceGraphBuilder
16+
public class ResourceGraphBuilder
1717
{
1818
private readonly IJsonApiOptions _options;
1919
private readonly ILogger<ResourceGraphBuilder> _logger;
@@ -22,7 +22,7 @@ public class ResourceGraphBuilder : IResourceGraphBuilder
2222
public ResourceGraphBuilder(IJsonApiOptions options, ILoggerFactory loggerFactory)
2323
{
2424
_options = options;
25-
_logger = loggerFactory.CreateLogger<ResourceGraphBuilder>();
25+
_logger = loggerFactory?.CreateLogger<ResourceGraphBuilder>();
2626
}
2727

2828
/// <inheritdoc />
@@ -44,15 +44,15 @@ private void SetResourceLinksOptions(ResourceContext resourceContext)
4444
}
4545

4646
/// <inheritdoc />
47-
public IResourceGraphBuilder AddResource<TResource>(string publicResourceName = null) where TResource : class, IIdentifiable<int>
47+
public ResourceGraphBuilder AddResource<TResource>(string publicResourceName = null) where TResource : class, IIdentifiable<int>
4848
=> AddResource<TResource, int>(publicResourceName);
4949

5050
/// <inheritdoc />
51-
public IResourceGraphBuilder AddResource<TResource, TId>(string publicResourceName = null) where TResource : class, IIdentifiable<TId>
51+
public ResourceGraphBuilder AddResource<TResource, TId>(string publicResourceName = null) where TResource : class, IIdentifiable<TId>
5252
=> AddResource(typeof(TResource), typeof(TId), publicResourceName);
5353

5454
/// <inheritdoc />
55-
public IResourceGraphBuilder AddResource(Type resourceType, Type idType = null, string publicResourceName = null)
55+
public ResourceGraphBuilder AddResource(Type resourceType, Type idType = null, string publicResourceName = null)
5656
{
5757
if (_resources.All(e => e.ResourceType != resourceType))
5858
{
@@ -65,7 +65,7 @@ public IResourceGraphBuilder AddResource(Type resourceType, Type idType = null,
6565
}
6666
else
6767
{
68-
_logger.LogWarning($"Entity '{resourceType}' does not implement '{nameof(IIdentifiable)}'.");
68+
_logger?.LogWarning($"Entity '{resourceType}' does not implement '{nameof(IIdentifiable)}'.");
6969
}
7070
}
7171

src/JsonApiDotNetCore/Extensions/ApplicationBuilderExtensions.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using JsonApiDotNetCore.Builders;
3+
using JsonApiDotNetCore.Formatters;
34
using JsonApiDotNetCore.Internal;
45
using JsonApiDotNetCore.Middleware;
56
using Microsoft.AspNetCore.Builder;
@@ -29,7 +30,10 @@ public static void UseJsonApi(this IApplicationBuilder builder, Action<MvcOption
2930
var jsonApiApplicationBuilder = builder.ApplicationServices.GetRequiredService<IJsonApiApplicationBuilder>();
3031
jsonApiApplicationBuilder.ConfigureMvcOptions = options =>
3132
{
33+
options.InputFormatters.Insert(0, builder.ApplicationServices.GetRequiredService<IJsonApiInputFormatter>());
34+
options.OutputFormatters.Insert(0, builder.ApplicationServices.GetRequiredService<IJsonApiOutputFormatter>());
3235
options.Conventions.Insert(0, builder.ApplicationServices.GetRequiredService<IJsonApiRoutingConvention>());
36+
3337
configureMvcOptions?.Invoke(options);
3438
};
3539

0 commit comments

Comments
 (0)