I have multiple let's say process services. These services have a property which I need to fill before using particular service. However these process services use also 1-n generator sub-services which also have same property as process service.
public interface IProcess
{
IEnumerable<string> metadata;
//...
}
public class Process1 : IProcess
{
public IEnumerable<string> Metadata {get; set;}
private readonly IGenerator1 Generator1;
private readonly IGenerator2 Generator2;
public Process1(
IGenerator1 generator1,
IGenerator2 generator2,
IEnumerable<string> metadata)
{
Generator1 = generator1;
Generator2 = generator2;
Metadata = metadata;
}
}
public interface IGenerator
{
IEnumerable<string> metadata;
//...
}
public class Generator1 : IGenerator
{
public IEnumerable<string> Metadata {get; set;}
private readonly ILogger Logger;
public Generator1(
ILogger logger,
IEnumerable<string> metadata)
{
Logger = logger;
Metadata = metadata;
}
}
I use DI and resolve dependencies in ServiceBuilder
public class ServiceBuilder
{
public ServiceBuilder()
{
var services = new ServiceCollection();
services.AddTransient<IProcess, Process1>();
services.AddSingleton<IProcessFactory, ProcessFactory>();
services.AddTransient<IDeliverySiteGenerator, DeliverySiteGenerator>();
services.AddTransient<INewConnectionErrandGenerator, NewConnectionErrandGenerator>();
//...
ServiceProvider = services.BuildServiceProvider();
}
}
And use ProcessFactory class and its' method GetProcess for retrieving processes I want to use. I add these processes in List<IProcess>
and then use this list for executing particular method from all retrieved IProcess services. configData
are provided by user input and it also include our wanted property IEnumerable<string> Metadata
.
public class ProcessFactory : IProcessFactory
{
private readonly IServiceProvider serviceProvider;
//...
public IProcess GetProcess(SomeConfigData configData)
{
var processExists = registeredProcesses.TryGetValue(configData, out var processType);
if (!processExists)
throw new InvalidArgumentException($"Process not supported.");
return (IProcess)serviceProvider.GetService(processType);
}
}
For now I added Metadata
to IProcess service after retrieving it by GetProcess
method while Metadata
has public setter. But it doesn't solve problem of how to pass it to generator sub-services. Don't want to go through all generator instances of process service and add Metadata
through public setter. Is there any way of achieving this?
One way to do that is creating a scoped service to provide access to the metadata:
public interface IMetadataAccessor
{
IEnumerable<string> Metadata { get; set; }
}
public class MetadataProcessor : IMetadataAccessor
{
public IEnumerable<string> Metadata { get; set; }
}
Register the service as scoped:
serviceCollection.AddScoped<IMetadataAccessor, MetadataProcessor>();
Change your process and generator classes to have IMetadataAccessor
injected via constructor, and read metadata like this:
public IEnumerable<string> Metadata => _metadataAccessor.Metadata;
Change your factory to instantiate process within a scope:
public Processor CreateProcessor(IEnumerable<string> metadata)
{
// Resolve services within a child scope
using (var scope = _services.CreateScope())
{
// Resolve the accessor service and set metadata
var accessor = scope.ServiceProvider.GetRequiredService<IMetadataAccessor>();
accessor.Metadata = metadata;
// Within the current scope, there is only one IMetadataAccessor.
// So both process and generator will be getting same accessor instance via the constructor.
// If we set metadata to the instance, all services can get the value.
var process = scope.ServiceProvider.GetRequiredService<Process>();
return process;
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.