Class UpdatingReferencedResource
- Namespace
- Acuit.Pinpoint.ResourceManagement
- Assembly
- Acuit.Pinpoint.ResourceManagement.Abstractions.dll
A base class for resources referenced by resource providers derived from ResourceProvider that updates the resource value upon "update-needed" signals.
public abstract class UpdatingReferencedResource : ReferencedResource, IDisposable
- Inheritance
-
UpdatingReferencedResource
- Implements
- Derived
- Inherited Members
Examples
This can be used to implement a resource that must be polled periodically like this:
internal class PolledResourceProvider : ResourceProvider // TODO: Typically, also implement IRegisteredResourceProvider
{
private readonly IErrorHandler _errorHandler;
private readonly ITimeService _timeService;
public PolledResourceProvider(IErrorHandler errorHandler, ITimeService timeService)
{
_errorHandler = errorHandler;
_timeService = timeService;
}
protected override ReferencedResource CreateReferencedResource(Uri url)
{
return new PolledReferencedResource(url, _errorHandler, _timeService);
}
}
internal class PolledReferencedResource : UpdatingReferencedResource
{
private static readonly TimeSpan s_pollPeriod = TimeSpan.FromMinutes(15);
private static readonly TimeSpan s_retryPeriod = TimeSpan.FromSeconds(15);
private readonly ITimeService _timeService;
private DelayChangeToken _updateNeededChangeToken;
public PolledReferencedResource(Uri url, IErrorHandler errorHandler, ITimeService timeService)
: base(url, errorHandler, timeService)
{
_timeService = timeService;
ResetUpdateNeededChangeToken(TimeSpan.Zero);
StartUpdating();
}
protected override void Dispose(bool disposing)
{
if (disposing)
_updateNeededChangeToken.Dispose();
base.Dispose(disposing);
}
private void ResetUpdateNeededChangeToken(TimeSpan delay)
{
var oldToken = _updateNeededChangeToken;
_updateNeededChangeToken = new DelayChangeToken(delay, _timeService);
oldToken?.Dispose();
}
protected override async Task<object> GetUpdatedResourceValueAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
try
{
var value = await PollValueAsync().ConfigureAwait(false); // TODO: poll the value
ResetUpdateNeededChangeToken(s_pollPeriod);
return value;
}
catch
{
ResetUpdateNeededChangeToken(s_retryPeriod); // Upon an error, retry sooner
throw;
}
}
protected override IChangeToken GetUpdateNeededToken() => _updateNeededChangeToken;
}
///
This can be used to implement a resource that derives its value from another resource like this:
internal class DerivedResourceProvider : ResourceProvider // TODO: Typically, also implement IRegisteredResourceProvider
{
private readonly IErrorHandler _errorHandler;
private readonly IResourceProvider _resourceProvider;
private readonly ITimeService _timeService;
public DerivedResourceProvider(IErrorHandler errorHandler, IResourceProvider resourceProvider, ITimeService timeService)
{
_errorHandler = errorHandler;
_resourceProvider = resourceProvider;
_timeService = timeService;
}
protected override ReferencedResource CreateReferencedResource(Uri url)
{
var sourceResourceUrl = DetermineSourceResourceUrl(url); // TODO: determine source resource URL for this derived resource
return new DerivedReferencedResource(url, sourceResourceUrl, _errorHandler, _resourceProvider, _timeService);
}
}
internal class DerivedReferencedResource : UpdatingReferencedResource
{
private readonly IResourceReference _sourceResourceReference;
public DerivedReferencedResource(Uri url, Uri sourceResourceUrl, IErrorHandler errorHandler, IResourceProvider resourceProvider, ITimeService timeService)
: base(url, errorHandler, timeService)
{
_sourceResourceReference = resourceProvider.CreateResourceReference(sourceResourceUrl);
StartUpdating();
}
protected override void Dispose(bool disposing)
{
if (disposing)
_sourceResourceReference.Dispose();
base.Dispose(disposing);
}
protected override async Task<object> GetUpdatedResourceValueAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
var sourceValue = await _sourceResourceReference.GetValueAsync(cancellationToken).ConfigureAwait(false);
return CalculateDerivedValue(sourceValue); // TODO: create derived value from source value
}
protected override IChangeToken GetUpdateNeededToken() => _sourceResourceReference.GetChangeToken();
}
Remarks
This provides common logic for scenarios such as:
- Resources that must be periodically polled for new values. (DelayChangeToken can be useful for implementing GetUpdateNeededToken().)
- Resources that monitor some external source for changes.
Implementations must do the following:
- Implement GetUpdatedResourceValueAsync(CancellationToken).
- Implement GetUpdateNeededToken().
- Call StartUpdating(), usually in the constructor.
Note that the token returned from GetChangeToken() will only be signaled upon the completion of the first update attempt, whether it succeeds or fails; and then subsequently upon each successful update when the value changes. If a subsequent update attempt fails, the change token will not be signaled (since the value did not change).
Constructors
UpdatingReferencedResource(Uri, IErrorHandler, ITimeService)
Initializes a new instance of the UpdatingReferencedResource class.
protected UpdatingReferencedResource(Uri url, IErrorHandler errorHandler, ITimeService timeService)
Parameters
url
UriThe resource URL.
errorHandler
IErrorHandlerThe error handler service.
timeService
ITimeServiceThe time service.
Exceptions
- ArgumentNullException
url
is null.- ArgumentNullException
errorHandler
is null.- ArgumentNullException
timeService
is null.
Methods
Dispose(bool)
Closes and releases all resources used by the ReferencedResource.
protected override void Dispose(bool disposing)
Parameters
Remarks
Derived classes should override this when they have any resources that should be disposed.
GetLastKnownValueAsync(CancellationToken)
Gets the last known value for this resource.
protected override Task<object> GetLastKnownValueAsync(CancellationToken cancellationToken)
Parameters
cancellationToken
CancellationTokenA cancellation token that can be used to request canceling waiting for the value.
Returns
- Task<object>
A task that represents the asynchronous operation. The value of its Result property contains the last known resource value.
Remarks
In general, this should immediately return the last known resource value, unless the initial asynchronous resource retrieval is still in progress, in which case
it should return a task that will complete when that attempt completes. Note that cancellationToken
will cancel waiting on that attempt to complete,
not cancel that attempt itself.
This might be called from multiple threads and before other asynchronous calls are complete.
Exceptions
- ObjectDisposedException
This object has been disposed.
- Exception
The resource could not be retrieved.
GetResourceValue(CancellationToken)
Gets the resource value. Derived classes can override the default behavior, which simply calls GetUpdatedResourceValueAsync(CancellationToken).
protected virtual Task<object> GetResourceValue(CancellationToken cancellationToken)
Parameters
cancellationToken
CancellationTokenA cancellation token that can be used to request canceling getting the updated resource value.
Returns
- Task<object>
A task that represents the asynchronous operation. The value of its Result property contains the resource value.
Exceptions
- Exception
The updated resource value could not be obtained. The implementation should throw a specific exception appropriate for the error. This can be thrown synchronously, or it can occur asynchronously, wrapped in an AggregateException as the faulted task's Exception.
GetUpdateNeededToken()
Gets a token that will signal a change when the resource value should be updated again.
protected abstract IChangeToken GetUpdateNeededToken()
Returns
- IChangeToken
The change token.
GetUpdatedResourceValueAsync(CancellationToken)
Gets the updated resource value. This should actually retrieve the resource value.
protected abstract Task<object> GetUpdatedResourceValueAsync(CancellationToken cancellationToken)
Parameters
cancellationToken
CancellationTokenA cancellation token that can be used to request canceling getting the updated resource value.
Returns
- Task<object>
A task that represents the asynchronous operation. The value of its Result property contains the resource value.
Exceptions
- Exception
The updated resource value could not be obtained. The implementation should throw a specific exception appropriate for the error. This can be thrown synchronously, or it can occur asynchronously, wrapped in an AggregateException as the faulted task's Exception.
StartUpdating()
Starts the automatic updater.
protected void StartUpdating()
Exceptions
- ObjectDisposedException
This object has been disposed.