-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathCachedHierarchicalTopicMappingService{T}.cs
More file actions
103 lines (91 loc) · 6.16 KB
/
CachedHierarchicalTopicMappingService{T}.cs
File metadata and controls
103 lines (91 loc) · 6.16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
/*==============================================================================================================================
| Author Ignia, LLC
| Client Ignia, LLC
| Project Topics Library
\=============================================================================================================================*/
using System.Collections.Concurrent;
using OnTopic.Models;
namespace OnTopic.Mapping.Hierarchical {
/*============================================================================================================================
| CLASS: CACHED HIERARCHICAL TOPIC MAPPING SERVICE
\---------------------------------------------------------------------------------------------------------------------------*/
/// <summary>
/// Provides a wrapper to a <see cref="IHierarchicalTopicMappingService{T}"/> implementation with support for caching.
/// </summary>
/// <remarks>
/// By comparison to the <see cref="HierarchicalTopicMappingService{T}"/>, the <see
/// cref="CachedHierarchicalTopicMappingService{T}"/> will automatically cache the <see
/// cref="IHierarchicalTopicViewModel{T}"/> graph for each action that uses the protected <see
/// cref="IHierarchicalTopicMappingService{T}.GetViewModelAsync(Topic, Int32, Func{Topic, Boolean})"/> method to construct
/// the graph. This is preferable over using e.g. the <see cref="CachedTopicMappingService"/> since the <see
/// cref="IHierarchicalTopicMappingService{T}"/> requires tight control over the shape of the <see
/// cref="IHierarchicalTopicViewModel{T}"/> graph. For instance, using a generic caching decorator for the mapping might
/// result in the edges of the graph being expanded due to other actions reusing cached instances (e.g., for page-level
/// navigation). To mitigate this, the <see cref="CachedHierarchicalTopicMappingService{T}"/> handles top-level caching at
/// the level of the hierarchy's root.
/// </remarks>
public class CachedHierarchicalTopicMappingService<T> : IHierarchicalTopicMappingService<T>
where T : class, IHierarchicalTopicViewModel<T>, new() {
/*==========================================================================================================================
| STATIC VARIABLES
\-------------------------------------------------------------------------------------------------------------------------*/
private readonly ConcurrentDictionary<int, T?> _cache = new();
private readonly IHierarchicalTopicMappingService<T> _hierarchicalTopicMappingService;
/*==========================================================================================================================
| CONSTRUCTOR
\-------------------------------------------------------------------------------------------------------------------------*/
/// <summary>
/// Initializes a new instance of a <see cref="CachedHierarchicalTopicMappingService{T}"/> based on an underlying
/// implementation of a <see cref="HierarchicalTopicMappingService{T}"/>.
/// </summary>
/// <returns>An instance of a <see cref="CachedHierarchicalTopicMappingService{T}"/>.</returns>
public CachedHierarchicalTopicMappingService(
IHierarchicalTopicMappingService<T> hierarchicalTopicMappingService
) {
_hierarchicalTopicMappingService = hierarchicalTopicMappingService;
}
/*==========================================================================================================================
| GET HIERARCHICAL ROOT
\-------------------------------------------------------------------------------------------------------------------------*/
/// <inheritdoc />
public Topic? GetHierarchicalRoot(Topic? currentTopic, int fromRoot = 2, string defaultRoot = "Web") =>
_hierarchicalTopicMappingService.GetHierarchicalRoot(currentTopic, fromRoot, defaultRoot);
/*==========================================================================================================================
| GET ROOT VIEW MODEL (ASYNC)
\-------------------------------------------------------------------------------------------------------------------------*/
/// <inheritdoc />
public async Task<T?> GetRootViewModelAsync(
Topic? sourceTopic,
int tiers = 1,
Func<Topic, bool>? validationDelegate = null
) {
/*------------------------------------------------------------------------------------------------------------------------
| Handle empty results
\-----------------------------------------------------------------------------------------------------------------------*/
if (sourceTopic is null) {
return await Task<T?>.FromResult<T?>(null).ConfigureAwait(false);
}
/*------------------------------------------------------------------------------------------------------------------------
| Handle cache hits
\-----------------------------------------------------------------------------------------------------------------------*/
if (_cache.TryGetValue(sourceTopic.Id, out var dto)) {
return await Task<T?>.FromResult<T?>(dto).ConfigureAwait(false);
}
/*------------------------------------------------------------------------------------------------------------------------
| Cache and return new version
\-----------------------------------------------------------------------------------------------------------------------*/
var viewModel = await GetViewModelAsync(sourceTopic, tiers, validationDelegate).ConfigureAwait(false);
return _cache.GetOrAdd(sourceTopic.Id, viewModel);
}
/*==========================================================================================================================
| GET VIEW MODEL (ASYNC)
\-------------------------------------------------------------------------------------------------------------------------*/
/// <inheritdoc />
public async Task<T?> GetViewModelAsync(
Topic? sourceTopic,
int tiers = 1,
Func<Topic, bool>? validationDelegate = null
) =>
await _hierarchicalTopicMappingService.GetViewModelAsync(sourceTopic, tiers, validationDelegate).ConfigureAwait(false);
} //Class
} //Namespace