Scope
Services can be composed to use different scopes. Local scoped service can be created for a specific purpose, and be thrown away once purpose is completed.
In the following example TypeRequest is handled and cached in applicationScope and TypeBuilderRequest by buildScope. After building a type, the builder classes are discarded.
// Create application-scope service with cache
IService applicationScope = Services.Create(ServiceHandlers.Instance);
// Place instance here
object instance;
// Temporary scope for building 'instance'
{
// Create build scoped service with cache to be disposed
using var buildScope = Services.Create((applicationScope, EmitHandlers.Instance, RequestHandlers.Instance));
// Create type building request
IRequestFor<TypeBuilder> typeBuilder = new TypeBuilderRequest("HelloWorldClass");
// Add ToString() -method
typeBuilder = typeBuilder.Append(ToStringRequest.Create("Hello World"));
// Type request
IRequestFor<Type> typeRequest = new TypeRequest(typeBuilder);
// Instance request
IRequestFor<object> newRequest = new NewRequest(typeRequest);
// Create instance
instance = buildScope.GetRequired<IRequestFor<object>, object>(newRequest);
}
// Scope is closed and type builder is disposed, type and instance remain in 'applicationScope'.
Console.WriteLine(instance);
Request as a tree, and by cache location.
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ applicationScope ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ NewRequest └── Type = TypeRequest ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ buildScope ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ └── Name = ContextRequest├── Key = "System.Reflection.Emit.TypeBuilder" ├── Value = TypeBuilderRequest │ └── Name = "HelloWorldClass" └── Requests[0] = BatchRequest ├── Requests[0] = Emit │ ├── Opcode = ldstr │ ├── Parameters[0] = "Hello World" │ └── ILGenerator = ILGeneratorRequest │ └── Builder = MethodBuilderRequest │ ├── Name = "ToString" │ ├── Attributes = PrivateScope, Public, Virtual, HideBySig │ └── ReturnType = System.String └── Requests[1] = Emit ├── Opcode = ret └── ILGenerator = ILGeneratorRequest ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
Another way to create scope is with IServiceScopeFactory service. It uses transient cache for all locally constructed instances except those that have ServiceDescription at ServiceLifetime.Singleton lifetime. They are constructed, cached and disposed at parent service.
// Create application-scope service with cache
IService applicationScope = Services.Create((ServiceHandlers.Instance, ServiceScopeHandler.Instance, EmitHandlers.Instance, RequestHandlers.Instance));
// Place instance here
object instance;
// Temporary scope for building 'instance'
{
// Create transient scope
using IServiceScope scope = ((IServiceScopeFactory)applicationScope.GetService(typeof(IServiceScopeFactory))!).CreateScope();
// Create service
IService scopedService = (IService)scope.ServiceProvider;
// Create request
IRequestFor<TypeBuilder> typeBuilder = new TypeBuilderRequest("HelloWorldClass");
// Add ToString() -method
typeBuilder = typeBuilder.Append(ToStringRequest.Create("Hello World"));
// Type request
IRequestFor<Type> typeRequest = new TypeRequest(typeBuilder);
// Instance request
IRequestFor<object> newRequest = new NewRequest(typeRequest);
// Create instance
instance = scopedService.GetRequired<IRequestFor<object>, object>(newRequest);
}
// Scope is closed and type builder is disposed, type and instance remain in 'applicationScope'.
Console.WriteLine(instance);
Full Example
Full example
using System;
using System.Collections.Generic;
using System.Reflection.Emit;
using Avalanche.Emit;
using Avalanche.Service;
using Microsoft.Extensions.DependencyInjection;
public class service_scope
{
public static void Run()
{
{
// <01>
// Create application-scope service with cache
IService applicationScope = Services.Create(ServiceHandlers.Instance);
// Place instance here
object instance;
// Temporary scope for building 'instance'
{
// Create build scoped service with cache to be disposed
using var buildScope = Services.Create((applicationScope, EmitHandlers.Instance, RequestHandlers.Instance));
// Create type building request
IRequestFor<TypeBuilder> typeBuilder = new TypeBuilderRequest("HelloWorldClass");
// Add ToString() -method
typeBuilder = typeBuilder.Append(ToStringRequest.Create("Hello World"));
// Type request
IRequestFor<Type> typeRequest = new TypeRequest(typeBuilder);
// Instance request
IRequestFor<object> newRequest = new NewRequest(typeRequest);
// Create instance
instance = buildScope.GetRequired<IRequestFor<object>, object>(newRequest);
}
// Scope is closed and type builder is disposed, type and instance remain in 'applicationScope'.
Console.WriteLine(instance);
// </01>
// Get cache
(applicationScope as IEntryProviderBase).TryGetEntryCache(out IEntryCacheBase? cache);
// Disconnect all cache lines
cache!.TryDisconnectAll(out System.Collections.Generic.IEnumerable<KeyValuePair<object, IEntry>>? cacheLines);
//
foreach (var line in cacheLines!)
{
Console.WriteLine(line);
}
}
{
// <02>
// Create a service with cache
IService applicationScope = Services.Create(ServiceHandlers.Instance);
// Temporary scope
{
// Create build scoped service with cache to be disposed
using var buildScope = Services.Create((applicationScope, EmitHandlers.Instance, RequestHandlers.Instance));
// Print service as tree
Console.WriteLine(buildScope.ToString());
}
// </02>
}
{
// <03>
// Create application-scope service with cache
IService applicationScope = Services.Create((ServiceHandlers.Instance, ServiceScopeHandler.Instance, EmitHandlers.Instance, RequestHandlers.Instance));
// Place instance here
object instance;
// Temporary scope for building 'instance'
{
// Create transient scope
using IServiceScope scope = ((IServiceScopeFactory)applicationScope.GetService(typeof(IServiceScopeFactory))!).CreateScope();
// Create service
IService scopedService = (IService)scope.ServiceProvider;
// Create request
IRequestFor<TypeBuilder> typeBuilder = new TypeBuilderRequest("HelloWorldClass");
// Add ToString() -method
typeBuilder = typeBuilder.Append(ToStringRequest.Create("Hello World"));
// Type request
IRequestFor<Type> typeRequest = new TypeRequest(typeBuilder);
// Instance request
IRequestFor<object> newRequest = new NewRequest(typeRequest);
// Create instance
instance = scopedService.GetRequired<IRequestFor<object>, object>(newRequest);
}
// Scope is closed and type builder is disposed, type and instance remain in 'applicationScope'.
Console.WriteLine(instance);
// </03>
}
}
}