runtime: [Bug]: At runtime sometimes the wrong overload is selected.
Description
For some reason in my code (my code looks fine to me), however at runtime somehow it calls the wrong overload effectively making the implementationFactory not run.
In my code I do:
/// <summary>
/// Service Collection Extensions for Loading Remora Plugins.
/// </summary>
[PublicAPI]
public static class ServiceCollectionExtensions
{
/// <summary>
/// Loads plugin services into the service collection.
/// </summary>
/// <param name="serviceCollection">The service collection.</param>
/// <param name="options">The options.</param>
/// <returns>The same service collection for chaining.</returns>
/// <remarks>
/// This also watches the plugin assemblies for modifications and then reloads/unloads
/// them automatically.
/// </remarks>
public static IServiceCollection AddPlugins(
this IServiceCollection serviceCollection,
PluginServiceOptions options)
{
var pluginService = new PluginService(options);
pluginService.LoadPlugins(
collection: serviceCollection);
return serviceCollection
.AddSingleton<PluginService>((serviceProvider) =>
{
pluginService.MigratePlugins(serviceProvider);
return pluginService;
})
.AddFileSystemWatcher(options);
}
private static IServiceCollection AddFileSystemWatcher(
this IServiceCollection serviceCollection,
PluginServiceOptions options)
{
return serviceCollection
.AddSingleton<FileSystemWatcher>(
(serviceProvider) =>
{
var pluginService = serviceProvider.GetRequiredService<PluginService>();
var fileSystemWatcher = new FileSystemWatcher(
PluginService.GetApplicationDirectory(),
options.Filter)
{
EnableRaisingEvents = true,
IncludeSubdirectories = true,
NotifyFilter = NotifyFilters.Attributes
| NotifyFilters.CreationTime
| NotifyFilters.DirectoryName
| NotifyFilters.FileName
| NotifyFilters.LastAccess
| NotifyFilters.LastWrite
| NotifyFilters.Security
| NotifyFilters.Size,
};
fileSystemWatcher.Changed += (_, e) =>
{
// Unload old plugin (file changed).
pluginService.UnloadPlugin(Path.GetFileNameWithoutExtension(e.FullPath));
// Load new one.
pluginService.LoadPlugin(e.FullPath);
};
fileSystemWatcher.Created += (_, e) =>
// Load Plugin (file created).
pluginService.LoadPlugin(e.FullPath);
fileSystemWatcher.Deleted += (_, e) =>
// Unload plugin (file deleted).
pluginService.UnloadPlugin(Path.GetFileNameWithoutExtension(e.FullPath));
fileSystemWatcher.Renamed += (_, e) =>
{
// Unload old plugin (file renamed).
pluginService.UnloadPlugin(Path.GetFileNameWithoutExtension(e.OldFullPath));
// Load new one.
pluginService.LoadPlugin(e.FullPath);
};
return fileSystemWatcher;
});
}
}
However for some reason both serviceCollection.AddSingleton<T>(implementationFactory)
calls get changed to serviceCollection.AddSingleton(Type serviceType)
calls.
Reproduction Steps
It might be because I am using 7.0.100 preview 7 SDK to compile, but it might not be that though.
Expected behavior
For the implementationFactory code in both calls to be ran right on build of the service provider.
Actual behavior
What happens is that at runtime, it calls the wrong overload.
Regression?
I think it worked with the 6.0.4xx .NET SDK, just when I installed the 7.0.1xx SDK is when I started having issues.
Known Workarounds
Currently I can only think about 1 thing: Uninstall the .NET 7 SDK temporarily (again).
Configuration
Version of .NET when the code runs: 6.0.8 (used 7.0.1xx SDK to compile .NET 6 application) OS: Windows 11 22H1 Dev Insiders Arch: x64 Specific to configuration: Unknown Blazor: Not using Blazor.
Other information
When I go to look at the above code in ILSpy I see this:
using System;
using System.IO;
using Microsoft.Extensions.DependencyInjection;
using Remora.Plugins.Services;
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddPlugins(this IServiceCollection serviceCollection, PluginServiceOptions options)
{
PluginService pluginService = new PluginService(options);
pluginService.LoadPlugins(serviceCollection);
return AddFileSystemWatcher(serviceCollection.AddSingleton(delegate(IServiceProvider serviceProvider)
{
pluginService.MigratePlugins(serviceProvider);
return pluginService;
}), options);
}
private static IServiceCollection AddFileSystemWatcher(this IServiceCollection serviceCollection, PluginServiceOptions options)
{
PluginServiceOptions options2 = options;
return serviceCollection.AddSingleton(delegate(IServiceProvider serviceProvider)
{
PluginService pluginService = serviceProvider.GetRequiredService<PluginService>();
FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(PluginService.GetApplicationDirectory(), options2.Filter)
{
EnableRaisingEvents = true,
IncludeSubdirectories = true,
NotifyFilter = (NotifyFilters.FileName | NotifyFilters.DirectoryName | NotifyFilters.Attributes | NotifyFilters.Size | NotifyFilters.LastWrite | NotifyFilters.LastAccess | NotifyFilters.CreationTime | NotifyFilters.Security)
};
fileSystemWatcher.Changed += delegate(object _, FileSystemEventArgs e)
{
pluginService.UnloadPlugin(Path.GetFileNameWithoutExtension(e.FullPath));
pluginService.LoadPlugin(e.FullPath);
};
fileSystemWatcher.Created += delegate(object _, FileSystemEventArgs e)
{
pluginService.LoadPlugin(e.FullPath);
};
fileSystemWatcher.Deleted += delegate(object _, FileSystemEventArgs e)
{
pluginService.UnloadPlugin(Path.GetFileNameWithoutExtension(e.FullPath));
};
fileSystemWatcher.Renamed += delegate(object _, RenamedEventArgs e)
{
pluginService.UnloadPlugin(Path.GetFileNameWithoutExtension(e.OldFullPath));
pluginService.LoadPlugin(e.FullPath);
};
return fileSystemWatcher;
});
}
}
Even the ILSpy code calls the right overload, however at runtime it does not for some reason. Perhaps the JIT is responsible?
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Comments: 15 (14 by maintainers)
Is there any way you can narrow the repo down further? There aren’t many of us that can take the time to learn how to create a discord bot and test Discord server.
Eliminating all external dependencies is ideal, if possible.