ServiceRequest<T>
When ServiceDescription is adapted to handler, the service requests placed on IServiceProvider are forwarded to IService as ServiceRequest<T>. All handlers can participate in the build process of requested services. Handlers can initialize, modify and decorate the result.
IServiceProvider.GetService(Type) requests are forwarded as ServiceRequest<T> requests.
MyClass instance = (MyClass)service.GetService(typeof(MyClass))!;
ServiceRequest<T> are received and processed by ServiceRequestHandler (included in ServiceHandlers). ServiceRequest<T> is the request on the consumer side.
MyClass instance = service.GetRequired<ServiceRequest<MyClass>, MyClass>(default);
ServiceRequestT.Create(type) constructs a ServiceRequest<T> for a specific run-time type.
// Create request
IServiceRequest request = ServiceRequestT.CreateCached(typeof(MyClass));
// Get service
MyClass instance = service.GetRequired<IServiceRequest, MyClass>(request);
IServiceProducerRequest<T>
IServiceProducerRequest<T> is the interface for the three producer side requests.
IServiceProducerRequest<T> ├── SingletonServiceRequest<T> ├── ScopedServiceRequest<T> └── TransientServiceRequest<T>
ServiceRequestHandler forwards ServiceRequest<T> as three sub-requests: SingletonServiceRequest<T>, ScopedServiceRequest<T> and TransientServiceRequest<T>.
Handler serves one of these request types and appends value in IServiceList<T>. The selected request type affects the dispose and cache policy of the result.
/// <summary>Creates lists with huge initial capacity.</summary>
public class LargeListBuilder : IHandlerBase
{
/// <summary>Constructs <![CDATA[List<>]]> instances</summary>
ConstructorT<int, IList> listConstructor = new(typeof(List<>));
/// <summary>Serve <![CDATA[ServiceRequest<List<>>]]></summary>
public void Handle<T>(IQuery<TransientServiceRequest<List<T>>, IServiceList<List<T>>> query)
{
// Unexpected status
if (query.Response.Status.ExcludeFlags() > EntryStatus.Value) return;
// Get response container
IServiceList<List<T>>? response = query.Response.Value<IServiceList<List<T>>>() ?? query.Response.PassValue<IServiceList<List<T>>>(new ServiceList<List<T>>());
// Create List<T> with Capacity = 1_000_000
IList largeList = listConstructor.Create(typeof(T), 1_000_000);
// Append to result
response.Add(largeList, new IServiceList.Line(Order: 0L, ToDispose: false));
}
}
// Create service collection
IServiceCollection serviceCollection = new ServiceCollection()
.AddHandler(new LargeListBuilder())
.AddHandlers(ServiceHandlers.Instance.ServiceRequestHandler)
.AddCachePolicy(CachePolicies.Default);
// Create service
using var service = serviceCollection.BuildAvalancheServiceProvider();
// Create list with Capacity = 1_000_000
List<int> instance = service.GetRequiredService<List<int>>();
Handlers participate in service query by modifiying IServiceList<T>.
/// <summary>Participate in <![CDATA[IEnumerable<string>]]> service request</summary>
public class StringsService : IHandlerBase
{
/// <summary></summary>
[Order(1000)] // After ServiceDescriptor (0)
public void Handle(IQuery<SingletonServiceRequest<string>, IServiceList<string>> query)
{
// Unexpected status
if (query.Response.Status.ExcludeFlags() > EntryStatus.Value) return;
// Get response container
IServiceList<string>? list = query.Response.Value<IServiceList<string>>() ?? query.Response.PassValue<IServiceList<string>>(new ServiceList<string>());
// String to add to service enumeration
string str = "Participated in service request (first line)";
// Append as first result value (Order = long.MinValue)
list.Add(str, new IServiceList.Line(Order: long.MinValue, ToDispose: false));
// String to add to service enumeration
str = "Participated in service request (last line)";
// Append as last result value (Order = long.MaxValue)
list.Add(str, new IServiceList.Line(Order: long.MaxValue, ToDispose: false));
}
}
// Create service collection
IServiceCollection serviceCollection = new ServiceCollection()
.AddHandlers(ServiceHandlers.Instance.ServiceRequestHandler)
.AddSingleton<string>("Hello")
.AddSingleton<string>("World")
.AddHandler(new StringsService());
// Create service provider
using var service = serviceCollection.BuildAvalancheServiceProvider();
// Request service IEnumerable<string>
IEnumerable<string> strings = service.GetRequiredService<IEnumerable<string>>();
// Print four strings
foreach (var str in strings) Console.WriteLine(str);
// "Participated in service request (first line)"
// "Hello"
// "World"
// "Participated in service request(last line)"
IServiceList<T>
/// <summary>
/// List that has elements and associated sort order.
///
/// Elements and order values are in separate sub-lists, so that a reference to element and order lists can be taken distictively.
///
/// List not maintained in sorted order, but must be put into order with explicit <see cref="Sort"/> call.
///
/// List has mutability state, and throws <see cref="InvalidOperationException"/> if is modified after put into read-only state.
/// </summary>
public interface IServiceList : IReadOnly, IDisposable
{
/// <summary>Get element type</summary>
Type ElementType { get; }
/// <summary>Get element at index.</summary>
object this[int index] { get; }
/// <summary>Elements as <![CDATA[IList<T>]]></summary>
object Elements { get; set; }
/// <summary>Orders, each line corresponds to line in <see cref="Elements"/></summary>
IList<Line> Lines { get; set; }
/// <summary>Get number of lines</summary>
int Count { get; }
/// <summary>Sort <see cref="Elements"/> by <see cref="Lines"/> values in ascending order. Must be in mutable-state.</summary>
void Sort();
/// <summary>Sort <see cref="Elements"/> by <see cref="Lines"/> values in decending order. Must be in mutable-state.</summary>
void InverseSort();
/// <summary>Add <paramref name="element"/> with associated order value <paramref name="order"/>.</summary>
void Add(object element, Line line);
/// <summary>object that can be used to synchronize the access.</summary>
object SyncRoot { get; }
/// <summary>Create T[]</summary>
Array ToArray();
/// <summary>Add all elements and lines from <paramref name="listFrom"/>.</summary>
void AddAll(IServiceList listFrom);
/// <summary>Service meta info</summary>
public record struct Line(long Order, bool ToDispose);
}
/// <summary>
/// List that has elements and associated sort order.
///
/// Elements and order values are in separate sub-lists, so that a reference to element and order lists can be taken distictively.
///
/// List is not maintained in sorted order, but must be put into order with explicit <see cref="IServiceList.Sort"/> call.
///
/// List has mutability state, and throws <see cref="InvalidOperationException"/> if is modified after put into read-only state.
/// </summary>
public interface IServiceList<T> : IServiceList
{
/// <summary></summary>
new IList<T> Elements { get; set; }
/// <summary>Add <paramref name="element"/> with associated order value <paramref name="order"/>.</summary>
void Add(T element, Line line);
}
Full Example
Full example
using System;
using System.Collections;
using System.Collections.Generic;
using Avalanche.Service;
using Avalanche.Utilities;
using Microsoft.Extensions.DependencyInjection;
using static System.Console;
public class di_servicerequest
{
public static void Run()
{
{
// Create service collection
IServiceCollection serviceCollection = new ServiceCollection()
.AddHandlers(ServiceHandlers.Instance.ServiceRequestHandler)
.AddCachePolicy(CachePolicies.Default)
.AddTransient<MyClass>();
// Create service
using IServiceDisposable service = serviceCollection.BuildAvalancheServiceProvider();
// Get instance
// <01>
MyClass instance = service.GetRequired<ServiceRequest<MyClass>, MyClass>(default);
// </01>
WriteLine(instance);
}
{
// Create service collection
IServiceCollection serviceCollection = new ServiceCollection()
.AddHandlers(ServiceHandlers.Instance.ServiceRequestHandler)
.AddCachePolicy(CachePolicies.Default)
.AddTransient<MyClass>();
// Create service
using IServiceDisposable service = serviceCollection.BuildAvalancheServiceProvider();
// <02>
// Create request
IServiceRequest request = ServiceRequestT.CreateCached(typeof(MyClass));
// Get service
MyClass instance = service.GetRequired<IServiceRequest, MyClass>(request);
// </02>
WriteLine(instance);
}
{
// Create service collection
IServiceCollection serviceCollection = new ServiceCollection()
.AddHandlers(ServiceHandlers.Instance.ServiceRequestHandler)
.AddCachePolicy(CachePolicies.Default)
.AddTransient<MyClass>();
// Create service
using IServiceDisposable service = serviceCollection.BuildAvalancheServiceProvider();
// Get instance
// <03>
MyClass instance = (MyClass)service.GetService(typeof(MyClass))!;
// </03>
WriteLine(instance);
}
{
// Create service collection
IServiceCollection serviceCollection = new ServiceCollection()
.AddHandlers(ServiceHandlers.Instance.ServiceRequestHandler)
.AddCachePolicy(CachePolicies.Default)
.AddTransient<MyClass>();
// Create service
using IServiceDisposable service = serviceCollection.BuildAvalancheServiceProvider();
// <04>
// Create request
IServiceRequest request = ServiceRequestT.CreateCached(typeof(MyClass));
// Get instance
MyClass instance = service.GetRequired<IServiceRequest, MyClass>(request);
// </04>
WriteLine(instance);
}
{
// <31>
// Create service collection
IServiceCollection serviceCollection = new ServiceCollection()
.AddHandler(new LargeListBuilder())
.AddHandlers(ServiceHandlers.Instance.ServiceRequestHandler)
.AddCachePolicy(CachePolicies.Default);
// Create service
using var service = serviceCollection.BuildAvalancheServiceProvider();
// Create list with Capacity = 1_000_000
List<int> instance = service.GetRequiredService<List<int>>();
// </31>
}
{
// <41>
// Create service collection
IServiceCollection serviceCollection = new ServiceCollection()
.AddHandlers(ServiceHandlers.Instance.ServiceRequestHandler)
.AddSingleton<string>("Hello")
.AddSingleton<string>("World")
.AddHandler(new StringsService());
// Create service provider
using var service = serviceCollection.BuildAvalancheServiceProvider();
// Request service IEnumerable<string>
IEnumerable<string> strings = service.GetRequiredService<IEnumerable<string>>();
// Print four strings
foreach (var str in strings) Console.WriteLine(str);
// "Participated in service request (first line)"
// "Hello"
// "World"
// "Participated in service request(last line)"
// </41>
}
}
// <MyClass>
/// <summary></summary>
public class MyClass
{
/// <summary></summary>
public MyClass()
{
}
}
// </MyClass>
// <LargeListBuilder>
/// <summary>Creates lists with huge initial capacity.</summary>
public class LargeListBuilder : IHandlerBase
{
/// <summary>Constructs <![CDATA[List<>]]> instances</summary>
ConstructorT<int, IList> listConstructor = new(typeof(List<>));
/// <summary>Serve <![CDATA[ServiceRequest<List<>>]]></summary>
public void Handle<T>(IQuery<TransientServiceRequest<List<T>>, IServiceList<List<T>>> query)
{
// Unexpected status
if (query.Response.Status.ExcludeFlags() > EntryStatus.Value) return;
// Get response container
IServiceList<List<T>>? response = query.Response.Value<IServiceList<List<T>>>() ?? query.Response.PassValue<IServiceList<List<T>>>(new ServiceList<List<T>>());
// Create List<T> with Capacity = 1_000_000
IList largeList = listConstructor.Create(typeof(T), 1_000_000);
// Append to result
response.Add(largeList, new IServiceList.Line(Order: 0L, ToDispose: false));
}
}
// </LargeListBuilder>
// <42>
/// <summary>Participate in <![CDATA[IEnumerable<string>]]> service request</summary>
public class StringsService : IHandlerBase
{
/// <summary></summary>
[Order(1000)] // After ServiceDescriptor (0)
public void Handle(IQuery<SingletonServiceRequest<string>, IServiceList<string>> query)
{
// Unexpected status
if (query.Response.Status.ExcludeFlags() > EntryStatus.Value) return;
// Get response container
IServiceList<string>? list = query.Response.Value<IServiceList<string>>() ?? query.Response.PassValue<IServiceList<string>>(new ServiceList<string>());
// String to add to service enumeration
string str = "Participated in service request (first line)";
// Append as first result value (Order = long.MinValue)
list.Add(str, new IServiceList.Line(Order: long.MinValue, ToDispose: false));
// String to add to service enumeration
str = "Participated in service request (last line)";
// Append as last result value (Order = long.MaxValue)
list.Add(str, new IServiceList.Line(Order: long.MaxValue, ToDispose: false));
}
}
// </42>
}