I'm using EventFlow to trace ETW events. For this I've created an ASP Net Core service that acts as a listener. I've configured my own custom output in my configuration file. And these are my Output and my OutputFactory classes:
class CustomOutput : IOutput
{
public Task SendEventsAsync(IReadOnlyCollection<EventData> events, long transmissionSequenceNumber, CancellationToken cancellationToken)
{
foreach(var e in events)
{
//...;
}
return Task.CompletedTask;
}
}
class CustomOutputFactory : IPipelineItemFactory<CustomOutput>
{
public CustomOutput CreateItem(IConfiguration configuration, IHealthReporter healthReporter)
{
return new CustomOutput();
}
}
This CustomOutput is instantiated only one time at start (when EventFlow pipeline is created) and it's used for all the events. The main method is this:
private static void Main()
{
try
{
using (var diagnosticsPipeline = ServiceFabricDiagnosticPipelineFactory.CreatePipeline("MyApplication-MyService-DiagnosticsPipeline"))
{
ServiceRuntime.RegisterServiceAsync("Stateless1Type",
context => new Stateless1(context)).GetAwaiter().GetResult();
ServiceEventSource.Current.ServiceTypeRegistered(Process.GetCurrentProcess().Id, typeof(Stateless1).Name);
Thread.Sleep(Timeout.Infinite);
}
}
catch (Exception e)
{
ServiceEventSource.Current.ServiceHostInitializationFailed(e.ToString());
throw;
}
}
The output and factory output types are referenced in the configuration file eventFlowConfig.json:
"extensions": [
{
"category": "outputFactory",
"type": "CustomOutput",
"qualifiedTypeName": "MyProyect.Service.MyApp.SqlOutputFactory, MyProyect.Service.MyApp"
}
]
Reference: Event aggregation and collection using EventFlow
Thus, the instance is created in the main method of my Program class, that is, before my Startup configuration methods are invoked.
How could I access from my Output class to my dependency container services if the container still does not exist when it's instantiated?
At the moment I've created a static property of type IServiceCollection and I set it from my Startup config method (using setter injection). I don't like this solution because I shouldn't use static access to services but I don't know another solution. It's this a valid practice?
class CustomOutput : IOutput
{
public static IServiceCollection Services { get; set; }
public Task SendEventsAsync(IReadOnlyCollection<EventData> events, long transmissionSequenceNumber, CancellationToken cancellationToken)
{
var sp = Services.BuildServiceProvider();
var loggerFactory = sp.GetService<ILoggerFactory>();
logger = loggerfactory.CreateLogger<CustomOutput>();
var repository = serviceProvider.GetService<IMyRepository>();
foreach (var e in events)
{
logger.LogDebug("event...");
repository.SaveEvent(e);
//...;
}
return Task.CompletedTask;
}
}
public class Startup
{
// Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
//..
CustomOutput.Services = services;
//..
}
}