Introduction
IService interfaces are used for issuing queries to service handlers.
// Create service
IService<IRequestFor<Type>, Type> service = Services.Create<IRequestFor<Type>, Type>(ServiceHandlers.Instance, CachePolicies.Default);
// Create request
IRequestFor<Type> typeRequest = new TypeRequest("System.String");
// Query type
Type type = service.GetRequired(typeRequest);
Interfaces
Each IService interface addresses a different aspect of service implementation.
IServiceProvider └── IServiceBase ├── IService │ └── IServiceDisposable ├── IServiceT │ └── IServiceOf<Response> │ └── IService<Request, Response> │ └── IServiceDisposable<Request, Response> │ ├── IServiceDecoration │ └── IServiceCast ├── IServiceObservable ├── IServiceLayer └── IServiceCastable ─── IServiceContainer
IService
/// <summary>Provides services for any request and response type.</summary>
public interface IService : IServiceBase
{
/// <summary>Get possible value.</summary>
/// <param name="request"></param>
/// <param name="cancelToken">call abort signal</param>
/// <param name="context">optional context parameters. If context parameters match to request, then query is not cached.</param>
/// <returns><typeparamref name="Response"/> value or null</returns>
/// <exception cref="ServiceException"></exception>
/// <exception cref="OperationCanceledException">if token is cancelled</exception>
/// <exception cref="ObjectDisposedException">Service is disposed</exception>
/// <exception cref="InvalidCastException">If result was not <typeparamref name="Response"/> type.</exception>
Response? Get<Request, Response>(in Request request, CancellationToken cancelToken = default, IDictionary<string, object>? context = null) where Request : notnull;
/// <summary>Get value and expect to get value.</summary>
/// <param name="request"></param>
/// <param name="cancelToken">call abort signal</param>
/// <param name="context">optional context parameters. If context parameters match to request, then query is not cached.</param>
/// <returns><typeparamref name="Response"/> value</returns>
/// <exception cref="ServiceException"></exception>
/// <exception cref="OperationCanceledException">if token is cancelled</exception>
/// <exception cref="ObjectDisposedException">Service is disposed</exception>
/// <exception cref="InvalidCastException">If result was not <typeparamref name="Response"/> type.</exception>
Response GetRequired<Request, Response>(in Request request, CancellationToken cancelToken = default, IDictionary<string, object>? context = null) where Request : notnull;
/// <summary>Try get <typeparamref name="Response"/> value.</summary>
/// <param name="request"></param>
/// <param name="response"></param>
/// <param name="cancelToken">call abort signal</param>
/// <param name="context">optional context parameters. If context parameters match to request, then query is not cached.</param>
/// <returns>true if was handled by <paramref name="service"/> and has <paramref name="response"/>.</returns>
/// <exception cref="ServiceException"></exception>
/// <exception cref="OperationCanceledException">if token is cancelled</exception>
/// <exception cref="ObjectDisposedException">Service is disposed</exception>
/// <exception cref="InvalidCastException">If result was not <typeparamref name="Response"/> type.</exception>
bool TryGet<Request, Response>(in Request request, [NotNullWhen(true)] out Response response, CancellationToken cancelToken = default, IDictionary<string, object>? context = null) where Request : notnull;
/// <summary>Get possible value</summary>
/// <param name="request"></param>
/// <param name="cancelToken">call abort signal</param>
/// <param name="context">optional context parameters. If context parameters match to request, then query is not cached.</param>
/// <returns>Task for <typeparamref name="Response"/> value.</returns>
/// <exception cref="ServiceException"></exception>
/// <exception cref="OperationCanceledException">if token is cancelled</exception>
/// <exception cref="ObjectDisposedException">Service is disposed</exception>
/// <exception cref="InvalidCastException">If result was not <typeparamref name="Response"/> type.</exception>
Task<Response?> GetAsync<Request, Response>(Request request, CancellationToken cancelToken = default, IDictionary<string, object>? context = null) where Request : notnull;
/// <summary>Get value and expect to get value.</summary>
/// <typeparam name="Request">The highest level of type the caller wants to provide keys with.</typeparam>
/// <typeparam name="Response">The highest level of type the caller wants read responses as.</typeparam>
/// <param name="request"></param>
/// <param name="cancelToken">call abort signal</param>
/// <param name="context">optional context parameters. If context parameters match to request, then query is not cached.</param>
/// <returns>Task for <typeparamref name="Response"/> value.</returns>
/// <exception cref="ServiceException"></exception>
/// <exception cref="OperationCanceledException">if token is cancelled</exception>
/// <exception cref="ObjectDisposedException">Service is disposed</exception>
/// <exception cref="InvalidCastException">If result was not <typeparamref name="Response"/> type.</exception>
Task<Response> GetRequiredAsync<Request, Response>(Request request, CancellationToken cancelToken = default, IDictionary<string, object>? context = null) where Request : notnull;
/// <param name="request"></param>
/// <param name="response"></param>
/// <param name="cancelToken">call abort signal</param>
/// <param name="context">optional context parameters. If context parameters match to request, then query is not cached.</param>
/// <returns>true if was handled by <paramref name="service"/> and has <paramref name="response"/>.</returns>
/// <exception cref="ServiceException"></exception>
/// <exception cref="OperationCanceledException">if token is cancelled</exception>
/// <exception cref="ObjectDisposedException">Service is disposed</exception>
/// <exception cref="InvalidCastException">If result was not <typeparamref name="Response"/> type.</exception>
bool TryGetInitialized<Request, Response>(in Request request, [NotNullWhen(true)] out Response response, CancellationToken cancelToken = default, IDictionary<string, object>? context = null) where Request : notnull;
/// <summary>Get initialized value. Return value once it has been assigned to <see cref="IEntry"/>. It may not be completed when returned.</summary>
/// <param name="request"></param>
/// <param name="cancelToken">call abort signal</param>
/// <param name="context">optional context parameters. If context parameters match to request, then query is not cached.</param>
/// <returns>Task for <typeparamref name="Response"/> value.</returns>
/// <exception cref="ServiceException"></exception>
/// <exception cref="OperationCanceledException">if token is cancelled</exception>
/// <exception cref="ObjectDisposedException">Service is disposed</exception>
/// <exception cref="InvalidCastException">If result was not <typeparamref name="Response"/> type.</exception>
Task<Response?> GetInitializedAsync<Request, Response>(Request request, CancellationToken cancelToken = default, IDictionary<string, object>? context = null) where Request : notnull;
/// <summary>Invoke <paramref name="request"/> but do not expect return value.</summary>
/// <param name="request"></param>
/// <param name="cancelToken">call abort signal</param>
/// <param name="context">optional context parameters. If context parameters match to request, then query is not cached.</param>
/// <returns>true if was handled</returns>
/// <exception cref="ServiceException"></exception>
/// <exception cref="OperationCanceledException">if token is cancelled</exception>
/// <exception cref="ObjectDisposedException"></exception>
bool TryInvoke<Request>(in Request request, CancellationToken cancelToken = default, IDictionary<string, object>? context = null) where Request : notnull;
/// <summary>Invoke <paramref name="request"/> but do not expect return value.</summary>
/// <param name="request"></param>
/// <param name="cancelToken">call abort signal</param>
/// <param name="context">optional context parameters. If context parameters match to request, then query is not cached.</param>
/// <returns>true if was handled.</returns>
/// <exception cref="ServiceException"></exception>
/// <exception cref="OperationCanceledException">if token is cancelled</exception>
Task<bool> InvokeAsync<Request>(Request request, CancellationToken cancelToken = default, IDictionary<string, object>? context = null) where Request : notnull;
}
IService<Request, Response>
/// <summary>Indicates that service has specific request response type.</summary>
public interface IServiceT : IServiceBase { }
/// <summary>Indicates that service has specific <typeparamref name="Response"/>.</summary>
public interface IServiceOf<Response> : IServiceT { }
/// <summary>Indicates that service has specific <typeparamref name="Request"/>.</summary>
public interface IService<Request> : IServiceT where Request : notnull
{
/// <summary>Invoke <paramref name="request"/> but do not expect any return value.</summary>
/// <param name="request"></param>
/// <param name="cancelToken">call abort signal</param>
/// <param name="context">optional context parameters. If context parameters match to request, then query is not cached.</param>
/// <returns>true if was handled</returns>
/// <exception cref="ServiceException"></exception>
/// <exception cref="OperationCanceledException">if token is cancelled</exception>
/// <exception cref="ObjectDisposedException"></exception>
bool TryInvoke(in Request request, CancellationToken cancelToken = default, IDictionary<string, object>? context = null);
/// <summary>Invoke <paramref name="request"/> but do not expect any return value.</summary>
/// <param name="request"></param>
/// <param name="cancelToken">call abort signal</param>
/// <param name="context">optional context parameters. If context parameters match to request, then query is not cached.</param>
/// <returns>true if was handled.</returns>
/// <exception cref="ServiceException"></exception>
/// <exception cref="OperationCanceledException">if token is cancelled</exception>
Task<bool> InvokeAsync(Request request, CancellationToken cancelToken = default, IDictionary<string, object>? context = null);
}
/// <summary>Indicates that service has specific <typeparamref name="Request"/> and <typeparamref name="Response"/> type.</summary>
public interface IService<Request, Response> : IService<Request>, IServiceOf<Response> where Request : notnull
{
/// <summary>Get possible value.</summary>
/// <param name="request"></param>
/// <param name="cancelToken">call abort signal</param>
/// <param name="context">optional context parameters. If context parameters match to request, then query is not cached.</param>
/// <returns><typeparamref name="Response"/> value or null</returns>
/// <exception cref="ServiceException"></exception>
/// <exception cref="OperationCanceledException">if token is cancelled</exception>
/// <exception cref="InvalidCastException">If result was not <typeparamref name="Response"/> type.</exception>
Response? Get(in Request request, CancellationToken cancelToken = default, IDictionary<string, object>? context = null);
/// <summary>Get value and expect to get value.</summary>
/// <param name="request"></param>
/// <param name="cancelToken">call abort signal</param>
/// <param name="context">optional context parameters. If context parameters match to request, then query is not cached.</param>
/// <returns><typeparamref name="Response"/> value</returns>
/// <exception cref="ServiceException"></exception>
/// <exception cref="OperationCanceledException">if token is cancelled</exception>
/// <exception cref="InvalidCastException">If result was not <typeparamref name="Response"/> type.</exception>
Response GetRequired(in Request request, CancellationToken cancelToken = default, IDictionary<string, object>? context = null);
/// <summary>Try get <typeparamref name="Response"/> value.</summary>
/// <param name="request"></param>
/// <param name="response"></param>
/// <param name="cancelToken">call abort signal</param>
/// <param name="context">optional context parameters. If context parameters match to request, then query is not cached.</param>
/// <returns>true if was handled by <paramref name="service"/> and has <paramref name="response"/>.</returns>
/// <exception cref="ServiceException"></exception>
/// <exception cref="OperationCanceledException">if token is cancelled</exception>
/// <exception cref="ObjectDisposedException">Service is disposed</exception>
/// <exception cref="InvalidCastException">If result was not <typeparamref name="Response"/> type.</exception>
bool TryGet(in Request request, out Response? response, CancellationToken cancelToken = default, IDictionary<string, object>? context = null);
/// <summary>Get possible value</summary>
/// <param name="request"></param>
/// <param name="cancelToken">call abort signal</param>
/// <param name="context">optional context parameters. If context parameters match to request, then query is not cached.</param>
/// <returns>Task for <typeparamref name="Response"/> value.</returns>
/// <exception cref="ServiceException"></exception>
/// <exception cref="OperationCanceledException">if token is cancelled</exception>
/// <exception cref="ObjectDisposedException">Service is disposed</exception>
/// <exception cref="InvalidCastException">If result was not <typeparamref name="Response"/> type.</exception>
Task<Response?> GetAsync(Request request, CancellationToken cancelToken = default, IDictionary<string, object>? context = null);
/// <summary>Get value and expect to get value.</summary>
/// <param name="request"></param>
/// <param name="cancelToken">call abort signal</param>
/// <param name="context">optional context parameters. If context parameters match to request, then query is not cached.</param>
/// <returns>Task for <typeparamref name="Response"/> value.</returns>
/// <exception cref="ServiceException"></exception>
/// <exception cref="OperationCanceledException">if token is cancelled</exception>
/// <exception cref="ObjectDisposedException">Service is disposed</exception>
/// <exception cref="InvalidCastException">If result was not <typeparamref name="Response"/> type.</exception>
Task<Response> GetRequiredAsync(Request request, CancellationToken cancelToken = default, IDictionary<string, object>? context = null);
/// <summary>Get initialized value. Return value once it has been assigned to <see cref="IEntry"/>. It may not be completed when returned.</summary>
/// <param name="request"></param>
/// <param name="response"></param>
/// <param name="cancelToken">call abort signal</param>
/// <param name="context">optional context parameters. If context parameters match to request, then query is not cached.</param>
/// <returns>true if was handled by <paramref name="service"/> and has <paramref name="response"/>.</returns>
/// <exception cref="ServiceException"></exception>
/// <exception cref="OperationCanceledException">if token is cancelled</exception>
/// <exception cref="ObjectDisposedException">Service is disposed</exception>
/// <exception cref="InvalidCastException">If result was not <typeparamref name="Response"/> type.</exception>
bool TryGetInitialized(in Request request, [NotNullWhen(true)] out Response response, CancellationToken cancelToken = default, IDictionary<string, object>? context = null);
/// <summary>Get initialized value. Return value once it has been assigned to <see cref="IEntry"/>. It may not be completed when returned.</summary>
/// <param name="request"></param>
/// <param name="cancelToken">call abort signal</param>
/// <param name="context">optional context parameters. If context parameters match to request, then query is not cached.</param>
/// <returns>Task for <typeparamref name="Response"/> value.</returns>
/// <exception cref="ServiceException"></exception>
/// <exception cref="OperationCanceledException">if token is cancelled</exception>
/// <exception cref="ObjectDisposedException">Service is disposed</exception>
/// <exception cref="InvalidCastException">If result was not <typeparamref name="Response"/> type.</exception>
Task<Response?> GetInitializedAsync(Request request, CancellationToken cancelToken = default, IDictionary<string, object>? context = null);
}
IServiceDecoration
/// <summary>Service provider that is based on decorating another <see cref="IService"/>. Optional information for the implementation</summary>
public interface IServiceDecoration : IServiceBase
{
/// <summary>Is decoration</summary>
bool IsServiceDecoration { get; }
/// <summary>The underlying <see cref="IService"/> this decoration is derivation of.</summary>
IServiceBase? DecorationSource { get; }
}
/// <summary>Decorates <see cref="IService"/> in an unspecified way.</summary>
public interface IServiceDecorator
{
/// <summary>Decorate <paramref name="service"/></summary>
/// <param name="service"></param>
/// <returns>Decorated version of <paramref name="service"/>. May or may not implement <see cref="IServiceDecoration"/>.</returns>
IServiceBase Decorate(IServiceBase service);
}
/// <summary>Indicates that the decoration affects only the casting of the <see cref="IServiceBase"/>.</summary>
public interface IServiceCast : IServiceDecoration
{
}
IServiceObservable
/// <summary>Service that can be observed for internal state changes.</summary>
public interface IServiceObservable : IServiceBase, IObservable<ServiceEvent>
{
}
/// <summary>Base class for service events</summary>
public record ServiceEvent(IServiceBase sender);
/// <summary>Service closed event</summary>
public record ServiceClosedEvent(IServiceBase sender) : ServiceEvent(sender);
IServiceLayer
/// <summary>Indicates that service utilizes a source layer</summary>
public interface IServiceLayer : IServiceBase
{
/// <summary>Source service</summary>
IServiceBase? SourceService { get; }
}
IServiceCastable
/// <summary>
/// Service that can cast to <see cref="IService{Request, Response}"/>.
/// </summary>
public interface IServiceCastable : IServiceBase
{
/// <summary>Try cast to <see cref="IService"/>.</summary>
bool TryCast([NotNullWhen(true)] out IService castedService);
/// <summary>Try cast to <see cref="IService{Request, Response}"/>.</summary>
bool TryCast<Request, Response>([NotNullWhen(true)] out IService<Request, Response> castedService) where Request : notnull;
/// <summary>Try cast to <see cref="IService{Request, Response}"/>.</summary>
bool TryCast(Type requestType, Type responseType, [NotNullWhen(true)] out IServiceT castedService);
}
IServiceContainer
/// <summary>Indicates that class binds a <see cref="IService"/> instance.</summary>
public interface IServiceContainer
{
/// <summary>Attached <see cref="IService"/>. </summary>
/// <exception cref="InvalidOperationException">If read-only</exception>
IService Service { get; set; }
}