Skip to content

Commit 7880f67

Browse files
author
Bart Koelman
committed
Added ISystemClock dependency to Passport
Replaced usages of DateTime.Now with ISystemClock or constants Added IResourceFactory/DefaultResourceFactory to abstract creating resource instances
1 parent 2697b4a commit 7880f67

33 files changed

+193
-102
lines changed

benchmarks/Serialization/JsonApiDeserializerBenchmarks.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.ComponentModel.Design;
44
using BenchmarkDotNet.Attributes;
55
using JsonApiDotNetCore.Configuration;
6+
using JsonApiDotNetCore.Internal;
67
using JsonApiDotNetCore.Internal.Contracts;
78
using JsonApiDotNetCore.Models;
89
using JsonApiDotNetCore.Serialization;
@@ -38,7 +39,7 @@ public JsonApiDeserializerBenchmarks()
3839
IResourceGraph resourceGraph = DependencyFactory.CreateResourceGraph(options);
3940
var targetedFields = new TargetedFields();
4041

41-
_jsonApiDeserializer = new RequestDeserializer(resourceGraph, new ServiceContainer(), targetedFields);
42+
_jsonApiDeserializer = new RequestDeserializer(resourceGraph, new DefaultResourceFactory(new ServiceContainer()), targetedFields);
4243
}
4344

4445
[Benchmark]

src/Examples/JsonApiDotNetCoreExample/Models/Passport.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,14 @@
33
using System.ComponentModel.DataAnnotations.Schema;
44
using System.Linq;
55
using JsonApiDotNetCore.Models;
6+
using JsonApiDotNetCoreExample.Data;
7+
using Microsoft.AspNetCore.Authentication;
68

79
namespace JsonApiDotNetCoreExample.Models
810
{
911
public class Passport : Identifiable
1012
{
13+
private readonly ISystemClock _systemClock;
1114
private int? _socialSecurityNumber;
1215

1316
[Attr]
@@ -18,7 +21,7 @@ public int? SocialSecurityNumber
1821
{
1922
if (value != _socialSecurityNumber)
2023
{
21-
LastSocialSecurityNumberChange = DateTime.Now;
24+
LastSocialSecurityNumberChange = _systemClock.UtcNow.LocalDateTime;
2225
_socialSecurityNumber = value;
2326
}
2427
}
@@ -60,5 +63,10 @@ public string BirthCountryName
6063

6164
[EagerLoad]
6265
public ICollection<Visa> GrantedVisas { get; set; }
66+
67+
public Passport(AppDbContext appDbContext)
68+
{
69+
_systemClock = appDbContext.SystemClock;
70+
}
6371
}
6472
}

src/Examples/JsonApiDotNetCoreExample/Services/CustomArticleService.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using Microsoft.Extensions.Logging;
99
using System.Collections.Generic;
1010
using System.Threading.Tasks;
11+
using JsonApiDotNetCore.Internal;
1112
using JsonApiDotNetCore.RequestServices;
1213

1314
namespace JsonApiDotNetCoreExample.Services
@@ -21,8 +22,9 @@ public CustomArticleService(
2122
IResourceRepository<Article, int> repository,
2223
IResourceContextProvider provider,
2324
IResourceChangeTracker<Article> resourceChangeTracker,
25+
IResourceFactory resourceFactory,
2426
IResourceHookExecutor hookExecutor = null)
25-
: base(queryParameters, options, loggerFactory, repository, provider, resourceChangeTracker, hookExecutor)
27+
: base(queryParameters, options, loggerFactory, repository, provider, resourceChangeTracker, resourceFactory, hookExecutor)
2628
{ }
2729

2830
public override async Task<Article> GetAsync(int id)

src/JsonApiDotNetCore/Builders/JsonApiApplicationBuilder.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ public void ConfigureServices()
188188
_services.AddScoped<IFieldsToSerialize, FieldsToSerialize>();
189189
_services.AddScoped(typeof(IResourceChangeTracker<>), typeof(DefaultResourceChangeTracker<>));
190190
_services.AddScoped<IQueryParameterActionFilter, QueryParameterActionFilter>();
191+
_services.AddScoped<IResourceFactory, DefaultResourceFactory>();
191192

192193
AddServerSerialization();
193194
AddQueryParameterServices();
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
using System;
2+
using JsonApiDotNetCore.Extensions;
3+
using JsonApiDotNetCore.Models;
4+
using Microsoft.Extensions.DependencyInjection;
5+
6+
namespace JsonApiDotNetCore.Internal
7+
{
8+
public interface IResourceFactory
9+
{
10+
public IIdentifiable CreateInstance(Type resourceType);
11+
public TResource CreateInstance<TResource>() where TResource : IIdentifiable;
12+
}
13+
14+
internal sealed class DefaultResourceFactory : IResourceFactory
15+
{
16+
private readonly IServiceProvider _serviceProvider;
17+
18+
public DefaultResourceFactory(IServiceProvider serviceProvider)
19+
{
20+
_serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider));
21+
}
22+
23+
public IIdentifiable CreateInstance(Type resourceType)
24+
{
25+
if (resourceType == null)
26+
{
27+
throw new ArgumentNullException(nameof(resourceType));
28+
}
29+
30+
return (IIdentifiable) InnerCreateInstance(resourceType, _serviceProvider);
31+
}
32+
33+
public TResource CreateInstance<TResource>() where TResource : IIdentifiable
34+
{
35+
return (TResource) InnerCreateInstance(typeof(TResource), _serviceProvider);
36+
}
37+
38+
private static object InnerCreateInstance(Type type, IServiceProvider serviceProvider)
39+
{
40+
bool hasSingleConstructorWithoutParameters = type.HasSingleConstructorWithoutParameters();
41+
42+
try
43+
{
44+
return hasSingleConstructorWithoutParameters
45+
? Activator.CreateInstance(type)
46+
: ActivatorUtilities.CreateInstance(serviceProvider, type);
47+
}
48+
catch (Exception exception)
49+
{
50+
throw new InvalidOperationException(hasSingleConstructorWithoutParameters
51+
? $"Failed to create an instance of '{type.FullName}' using its default constructor."
52+
: $"Failed to create an instance of '{type.FullName}' using injected constructor parameters.",
53+
exception);
54+
}
55+
}
56+
}
57+
}

src/JsonApiDotNetCore/Internal/TypeHelper.cs

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -238,39 +238,5 @@ public static object CreateInstance(Type type)
238238
throw new InvalidOperationException($"Failed to create an instance of '{type.FullName}' using its default constructor.", exception);
239239
}
240240
}
241-
242-
public static T CreateEntityInstance<T>(IServiceProvider serviceProvider)
243-
{
244-
return (T) CreateEntityInstance(typeof(T), serviceProvider);
245-
}
246-
247-
public static object CreateEntityInstance(Type type, IServiceProvider serviceProvider)
248-
{
249-
if (type == null)
250-
{
251-
throw new ArgumentNullException(nameof(type));
252-
}
253-
254-
if (serviceProvider == null)
255-
{
256-
throw new ArgumentNullException(nameof(serviceProvider));
257-
}
258-
259-
bool hasSingleConstructorWithoutParameters = type.HasSingleConstructorWithoutParameters();
260-
261-
try
262-
{
263-
return hasSingleConstructorWithoutParameters
264-
? Activator.CreateInstance(type)
265-
: ActivatorUtilities.CreateInstance(serviceProvider, type);
266-
}
267-
catch (Exception exception)
268-
{
269-
throw new InvalidOperationException(hasSingleConstructorWithoutParameters
270-
? $"Failed to create an instance of '{type.FullName}' using its default constructor."
271-
: $"Failed to create an instance of '{type.FullName}' using injected constructor parameters.",
272-
exception);
273-
}
274-
}
275241
}
276242
}

src/JsonApiDotNetCore/Serialization/Client/ResponseDeserializer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ namespace JsonApiDotNetCore.Serialization.Client
1313
/// </summary>
1414
public class ResponseDeserializer : BaseDocumentParser, IResponseDeserializer
1515
{
16-
public ResponseDeserializer(IResourceContextProvider contextProvider, IServiceProvider serviceProvider) : base(contextProvider, serviceProvider) { }
16+
public ResponseDeserializer(IResourceContextProvider contextProvider, IResourceFactory resourceFactory) : base(contextProvider, resourceFactory) { }
1717

1818
/// <inheritdoc/>
1919
public DeserializedSingleResponse<TResource> DeserializeSingle<TResource>(string body) where TResource : class, IIdentifiable

src/JsonApiDotNetCore/Serialization/Common/BaseDocumentParser.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,13 @@ namespace JsonApiDotNetCore.Serialization
2222
public abstract class BaseDocumentParser
2323
{
2424
protected readonly IResourceContextProvider _contextProvider;
25-
private readonly IServiceProvider _serviceProvider;
25+
private readonly IResourceFactory _resourceFactory;
2626
protected Document _document;
2727

28-
protected BaseDocumentParser(IResourceContextProvider contextProvider, IServiceProvider serviceProvider)
28+
protected BaseDocumentParser(IResourceContextProvider contextProvider, IResourceFactory resourceFactory)
2929
{
3030
_contextProvider = contextProvider;
31-
_serviceProvider = serviceProvider;
31+
_resourceFactory = resourceFactory;
3232
}
3333

3434
/// <summary>
@@ -142,7 +142,7 @@ private IIdentifiable ParseResourceObject(ResourceObject data)
142142
"If you have manually registered the resource, check that the call to AddResource correctly sets the public name.", null);
143143
}
144144

145-
var entity = (IIdentifiable)TypeHelper.CreateEntityInstance(resourceContext.ResourceType, _serviceProvider);
145+
var entity = _resourceFactory.CreateInstance(resourceContext.ResourceType);
146146

147147
entity = SetAttributes(entity, data.Attributes, resourceContext.Attributes);
148148
entity = SetRelationships(entity, data.Relationships, resourceContext.Relationships);
@@ -214,7 +214,7 @@ private void SetNavigation(IIdentifiable entity, HasOneAttribute attr, string re
214214
}
215215
else
216216
{
217-
var relatedInstance = (IIdentifiable)TypeHelper.CreateInstance(attr.RightType);
217+
var relatedInstance = _resourceFactory.CreateInstance(attr.RightType);
218218
relatedInstance.StringId = relatedId;
219219
attr.SetValue(entity, relatedInstance);
220220
}

src/JsonApiDotNetCore/Serialization/Server/RequestDeserializer.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System;
1+
using System;
2+
using JsonApiDotNetCore.Internal;
23
using JsonApiDotNetCore.Internal.Contracts;
34
using JsonApiDotNetCore.Models;
45

@@ -11,8 +12,8 @@ public class RequestDeserializer : BaseDocumentParser, IJsonApiDeserializer
1112
{
1213
private readonly ITargetedFields _targetedFields;
1314

14-
public RequestDeserializer(IResourceContextProvider contextProvider, IServiceProvider serviceProvider, ITargetedFields targetedFields)
15-
: base(contextProvider, serviceProvider)
15+
public RequestDeserializer(IResourceContextProvider contextProvider, IResourceFactory resourceFactory, ITargetedFields targetedFields)
16+
: base(contextProvider, resourceFactory)
1617
{
1718
_targetedFields = targetedFields;
1819
}

src/JsonApiDotNetCore/Services/DefaultResourceService.cs

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ public class DefaultResourceService<TResource, TId> :
3232
private readonly ISortService _sortService;
3333
private readonly IResourceRepository<TResource, TId> _repository;
3434
private readonly IResourceChangeTracker<TResource> _resourceChangeTracker;
35+
private readonly IResourceFactory _resourceFactory;
3536
private readonly ILogger _logger;
3637
private readonly IResourceHookExecutor _hookExecutor;
3738
private readonly IIncludeService _includeService;
@@ -45,6 +46,7 @@ public DefaultResourceService(
4546
IResourceRepository<TResource, TId> repository,
4647
IResourceContextProvider provider,
4748
IResourceChangeTracker<TResource> resourceChangeTracker,
49+
IResourceFactory resourceFactory,
4850
IResourceHookExecutor hookExecutor = null)
4951
{
5052
_includeService = queryParameters.FirstOrDefault<IIncludeService>();
@@ -56,6 +58,7 @@ public DefaultResourceService(
5658
_logger = loggerFactory.CreateLogger<DefaultResourceService<TResource, TId>>();
5759
_repository = repository;
5860
_resourceChangeTracker = resourceChangeTracker;
61+
_resourceFactory = resourceFactory;
5962
_hookExecutor = hookExecutor;
6063
_currentRequestResource = provider.GetResourceContext<TResource>();
6164
}
@@ -81,18 +84,28 @@ public virtual async Task DeleteAsync(TId id)
8184
{
8285
_logger.LogTrace($"Entering {nameof(DeleteAsync)}('{id}').");
8386

84-
var entity = TypeHelper.CreateInstance<TResource>();
85-
entity.Id = id;
86-
if (!IsNull(_hookExecutor, entity)) _hookExecutor.BeforeDelete(AsList(entity), ResourcePipeline.Delete);
87+
if (!IsNull(_hookExecutor))
88+
{
89+
var entity = _resourceFactory.CreateInstance<TResource>();
90+
entity.Id = id;
91+
92+
_hookExecutor.BeforeDelete(AsList(entity), ResourcePipeline.Delete);
93+
}
8794

88-
var succeeded = await _repository.DeleteAsync(entity.Id);
95+
var succeeded = await _repository.DeleteAsync(id);
8996
if (!succeeded)
9097
{
9198
string resourceId = TypeExtensions.GetResourceStringId<TResource, TId>(id);
9299
throw new ResourceNotFoundException(resourceId, _currentRequestResource.ResourceName);
93100
}
94101

95-
if (!IsNull(_hookExecutor, entity)) _hookExecutor.AfterDelete(AsList(entity), ResourcePipeline.Delete, succeeded);
102+
if (!IsNull(_hookExecutor))
103+
{
104+
var entity = _resourceFactory.CreateInstance<TResource>();
105+
entity.Id = id;
106+
107+
_hookExecutor.AfterDelete(AsList(entity), ResourcePipeline.Delete, succeeded);
108+
}
96109
}
97110

98111
public virtual async Task<IEnumerable<TResource>> GetAsync()
@@ -427,8 +440,9 @@ public DefaultResourceService(
427440
IResourceRepository<TResource, int> repository,
428441
IResourceContextProvider provider,
429442
IResourceChangeTracker<TResource> resourceChangeTracker,
443+
IResourceFactory resourceFactory,
430444
IResourceHookExecutor hookExecutor = null)
431-
: base(queryParameters, options, loggerFactory, repository, provider, resourceChangeTracker, hookExecutor)
445+
: base(queryParameters, options, loggerFactory, repository, provider, resourceChangeTracker, resourceFactory, hookExecutor)
432446
{ }
433447
}
434448
}

0 commit comments

Comments
 (0)