public async Task RebuildCatalogAsync()
        {
            var newCatalog = new Dictionary <string, ProbeInfo>();
            var files      = _probesDirectory.GetFiles("*.Probe.dll");

            _logger.LogTrace($"Found {files.Length} potential probe assemblies.");

            using var context = new SideLoadContext(_logger);
            foreach (var file in files)
            {
                try
                {
                    _logger.LogTrace($"Examining assembly: {file.Name}");
                    await using var stream = new FileStream(file.FullName, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, useAsync: true);
                    var assembly = context.LoadFromStream(stream);

                    var probeInfos = GetProbeInfos(file.FullName, assembly);
                    _logger.Log(
                        probeInfos.Length == 0 ? LogLevel.Warning : LogLevel.Information,
                        $"Discovered {probeInfos.Length} probe info(s) in assembly: {file.Name}.");

                    foreach (var probeInfo in probeInfos)
                    {
                        newCatalog.Add(probeInfo.Name, probeInfo);
                    }

                    Current = newCatalog;
                }
                catch (Exception ex)
                {
                    _logger.LogWarning(ex, $"Unable to load assembly at path: {file.FullName}");
                }
            }
        }
        public IProbe Create(string probeName)
        {
            if (probeName == null)
            {
                throw new ArgumentNullException(nameof(probeName));
            }

            _logger.LogTrace($"Creating probe: {probeName}");
            if (!_catalog.Current.TryGetValue(probeName, out var probeInfo))
            {
                throw new ArgumentOutOfRangeException(nameof(probeName), $"Probe named {probeName} not found.");
            }

            lock (_lock)
            {
                if (_probes.TryGetValue(probeName, out var context))
                {
                    return(context.Probe);
                }

                _logger.LogTrace($"Probe not yet loaded, side loading: {probeInfo}");
                var probeLogger = _loggerFactory.CreateLogger(probeInfo.TypeFullName);
                var loader      = new SideLoadContext(_loggerFactory.CreateLogger <SideLoadContext>());
                var assembly    = loader.LoadFromAssemblyPath(probeInfo.AssemblyLocation);
                var probe       = (IProbe)assembly.CreateInstance(probeInfo.TypeFullName, false, BindingFlags.Instance | BindingFlags.Public, null, new object[] { _configuration, probeLogger, _publisher }, CultureInfo.CurrentCulture, null);

                context = new ProbeContext(loader, probe);
                _probes.Add(probeInfo.Name, context);

                return(context.Probe);
            }
        }
 public ProbeContext(SideLoadContext context, IProbe probe)
 {
     Context = context ?? throw new ArgumentNullException(nameof(context));
     Probe   = probe ?? throw new ArgumentNullException(nameof(probe));
 }