Make DI services scoped
This commit is contained in:
@@ -14,18 +14,19 @@ public class InjectAttribute : Attribute;
|
|||||||
public partial class DiAutoload : Node
|
public partial class DiAutoload : Node
|
||||||
{
|
{
|
||||||
private ServiceProvider? _serviceProvider;
|
private ServiceProvider? _serviceProvider;
|
||||||
|
private IServiceScope? _currentScope;
|
||||||
|
|
||||||
public override void _EnterTree()
|
public override void _EnterTree()
|
||||||
{
|
{
|
||||||
GD.Print("[Injector] _EnterTree called");
|
GD.Print("[Injector] _EnterTree called");
|
||||||
var services = new ServiceCollection();
|
var services = new ServiceCollection();
|
||||||
// Register services here
|
// Register services here
|
||||||
services.AddSingleton<BuildService>();
|
services.AddScoped<BuildService>();
|
||||||
services.AddSingleton<RunService>();
|
services.AddScoped<RunService>();
|
||||||
services.AddSingleton<IdeFileExternalChangeHandler>();
|
services.AddScoped<IdeFileExternalChangeHandler>();
|
||||||
services.AddSingleton<IdeFileSavedToDiskHandler>();
|
services.AddScoped<IdeFileSavedToDiskHandler>();
|
||||||
services.AddSingleton<IdeFileWatcher>();
|
services.AddScoped<IdeFileWatcher>();
|
||||||
services.AddSingleton<IdeOpenTabsFileManager>();
|
services.AddScoped<IdeOpenTabsFileManager>();
|
||||||
|
|
||||||
_serviceProvider = services.BuildServiceProvider();
|
_serviceProvider = services.BuildServiceProvider();
|
||||||
GetTree().NodeAdded += OnNodeAdded;
|
GetTree().NodeAdded += OnNodeAdded;
|
||||||
@@ -37,6 +38,13 @@ public partial class DiAutoload : Node
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The solution has changed, so reset the scope to get new services
|
||||||
|
public void ResetScope()
|
||||||
|
{
|
||||||
|
_currentScope?.Dispose();
|
||||||
|
_currentScope = _serviceProvider!.CreateScope();
|
||||||
|
}
|
||||||
|
|
||||||
private void OnNodeAdded(Node node)
|
private void OnNodeAdded(Node node)
|
||||||
{
|
{
|
||||||
// Inject dependencies into every new node
|
// Inject dependencies into every new node
|
||||||
@@ -52,11 +60,18 @@ public partial class DiAutoload : Node
|
|||||||
{
|
{
|
||||||
if (Attribute.IsDefined(field, typeof(InjectAttribute)))
|
if (Attribute.IsDefined(field, typeof(InjectAttribute)))
|
||||||
{
|
{
|
||||||
var service = _serviceProvider!.GetService(field.FieldType);
|
if (_currentScope is null)
|
||||||
|
{
|
||||||
|
GD.PrintErr("[Injector] _currentScope was null when attempting to resolve service");
|
||||||
|
GetTree().Quit();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var service = _currentScope!.ServiceProvider.GetService(field.FieldType);
|
||||||
if (service is null)
|
if (service is null)
|
||||||
{
|
{
|
||||||
GD.PrintErr($"[Injector] No service registered for {field.FieldType}");
|
GD.PrintErr($"[Injector] No service registered for {field.FieldType}");
|
||||||
GetTree().Quit();
|
GetTree().Quit();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
field.SetValue(target, service);
|
field.SetValue(target, service);
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
using Godot;
|
using Godot;
|
||||||
using SharpIDE.Application.Features.SolutionDiscovery.VsPersistence;
|
using SharpIDE.Application.Features.SolutionDiscovery.VsPersistence;
|
||||||
|
using SharpIDE.Godot.Features.Build;
|
||||||
|
using SharpIDE.Godot.Features.Debug_;
|
||||||
using SharpIDE.Godot.Features.IdeDiagnostics;
|
using SharpIDE.Godot.Features.IdeDiagnostics;
|
||||||
using SharpIDE.Godot.Features.Problems;
|
using SharpIDE.Godot.Features.Problems;
|
||||||
|
using SharpIDE.Godot.Features.Run;
|
||||||
|
|
||||||
namespace SharpIDE.Godot.Features.BottomPanel;
|
namespace SharpIDE.Godot.Features.BottomPanel;
|
||||||
|
|
||||||
@@ -17,9 +20,9 @@ public partial class BottomPanelManager : Panel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Control _runPanel = null!;
|
private RunPanel _runPanel = null!;
|
||||||
private Control _debugPanel = null!;
|
private DebugPanel _debugPanel = null!;
|
||||||
private Control _buildPanel = null!;
|
private BuildPanel _buildPanel = null!;
|
||||||
private ProblemsPanel _problemsPanel = null!;
|
private ProblemsPanel _problemsPanel = null!;
|
||||||
private IdeDiagnosticsPanel _ideDiagnosticsPanel = null!;
|
private IdeDiagnosticsPanel _ideDiagnosticsPanel = null!;
|
||||||
|
|
||||||
@@ -27,9 +30,9 @@ public partial class BottomPanelManager : Panel
|
|||||||
|
|
||||||
public override void _Ready()
|
public override void _Ready()
|
||||||
{
|
{
|
||||||
_runPanel = GetNode<Control>("%RunPanel");
|
_runPanel = GetNode<RunPanel>("%RunPanel");
|
||||||
_debugPanel = GetNode<Control>("%DebugPanel");
|
_debugPanel = GetNode<DebugPanel>("%DebugPanel");
|
||||||
_buildPanel = GetNode<Control>("%BuildPanel");
|
_buildPanel = GetNode<BuildPanel>("%BuildPanel");
|
||||||
_problemsPanel = GetNode<ProblemsPanel>("%ProblemsPanel");
|
_problemsPanel = GetNode<ProblemsPanel>("%ProblemsPanel");
|
||||||
_ideDiagnosticsPanel = GetNode<IdeDiagnosticsPanel>("%IdeDiagnosticsPanel");
|
_ideDiagnosticsPanel = GetNode<IdeDiagnosticsPanel>("%IdeDiagnosticsPanel");
|
||||||
|
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ public partial class IdeRoot : Control
|
|||||||
[Inject] private readonly IdeFileExternalChangeHandler _fileExternalChangeHandler = null!;
|
[Inject] private readonly IdeFileExternalChangeHandler _fileExternalChangeHandler = null!;
|
||||||
[Inject] private readonly IdeFileWatcher _fileWatcher = null!;
|
[Inject] private readonly IdeFileWatcher _fileWatcher = null!;
|
||||||
[Inject] private readonly BuildService _buildService = null!;
|
[Inject] private readonly BuildService _buildService = null!;
|
||||||
|
[Inject] private readonly IdeOpenTabsFileManager _openTabsFileManager = null!;
|
||||||
|
|
||||||
public override void _EnterTree()
|
public override void _EnterTree()
|
||||||
{
|
{
|
||||||
@@ -52,7 +53,8 @@ public partial class IdeRoot : Control
|
|||||||
|
|
||||||
public override void _ExitTree()
|
public override void _ExitTree()
|
||||||
{
|
{
|
||||||
_fileWatcher.Dispose();
|
_fileWatcher?.Dispose();
|
||||||
|
GetTree().GetRoot().FocusExited -= OnFocusExited;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void _Ready()
|
public override void _Ready()
|
||||||
@@ -80,8 +82,15 @@ public partial class IdeRoot : Control
|
|||||||
_cleanSlnButton.Pressed += OnCleanSlnButtonPressed;
|
_cleanSlnButton.Pressed += OnCleanSlnButtonPressed;
|
||||||
_restoreSlnButton.Pressed += OnRestoreSlnButtonPressed;
|
_restoreSlnButton.Pressed += OnRestoreSlnButtonPressed;
|
||||||
GodotGlobalEvents.Instance.BottomPanelVisibilityChangeRequested.Subscribe(async show => await this.InvokeAsync(() => _invertedVSplitContainer.InvertedSetCollapsed(!show)));
|
GodotGlobalEvents.Instance.BottomPanelVisibilityChangeRequested.Subscribe(async show => await this.InvokeAsync(() => _invertedVSplitContainer.InvertedSetCollapsed(!show)));
|
||||||
|
GetTree().GetRoot().FocusExited += OnFocusExited;
|
||||||
_nodeReadyTcs.SetResult();
|
_nodeReadyTcs.SetResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Problematic, as this is called even when the focus shifts to an embedded subwindow, such as a popup
|
||||||
|
private void OnFocusExited()
|
||||||
|
{
|
||||||
|
_ = Task.GodotRun(async () => await _openTabsFileManager.SaveAllOpenFilesAsync());
|
||||||
|
}
|
||||||
|
|
||||||
private void OnRunMenuButtonPressed()
|
private void OnRunMenuButtonPressed()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -21,8 +21,6 @@ public partial class IdeWindow : Control
|
|||||||
private IdeRoot? _ideRoot;
|
private IdeRoot? _ideRoot;
|
||||||
private SlnPicker? _slnPicker;
|
private SlnPicker? _slnPicker;
|
||||||
|
|
||||||
[Inject] private readonly IdeOpenTabsFileManager _openTabsFileManager = null!;
|
|
||||||
|
|
||||||
public override void _Ready()
|
public override void _Ready()
|
||||||
{
|
{
|
||||||
GD.Print("IdeWindow _Ready called");
|
GD.Print("IdeWindow _Ready called");
|
||||||
@@ -31,7 +29,6 @@ public partial class IdeWindow : Control
|
|||||||
MSBuildLocator.RegisterDefaults();
|
MSBuildLocator.RegisterDefaults();
|
||||||
GodotServiceDefaults.AddServiceDefaults();
|
GodotServiceDefaults.AddServiceDefaults();
|
||||||
Singletons.AppState = AppStateLoader.LoadAppStateFromConfigFile();
|
Singletons.AppState = AppStateLoader.LoadAppStateFromConfigFile();
|
||||||
GetWindow().FocusExited += OnFocusExited;
|
|
||||||
//GetWindow().SetMinSize(new Vector2I(1152, 648));
|
//GetWindow().SetMinSize(new Vector2I(1152, 648));
|
||||||
Callable.From(() => PickSolution(true)).CallDeferred();
|
Callable.From(() => PickSolution(true)).CallDeferred();
|
||||||
}
|
}
|
||||||
@@ -47,12 +44,6 @@ public partial class IdeWindow : Control
|
|||||||
// PrintOrphanNodes();
|
// PrintOrphanNodes();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Problematic, as this is called even when the focus shifts to an embedded subwindow, such as a popup
|
|
||||||
private void OnFocusExited()
|
|
||||||
{
|
|
||||||
_ = Task.GodotRun(async () => await _openTabsFileManager.SaveAllOpenFilesAsync());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void PickSolution(bool fullscreen = false)
|
public void PickSolution(bool fullscreen = false)
|
||||||
{
|
{
|
||||||
if (_slnPicker is not null) throw new InvalidOperationException("Solution picker is already active");
|
if (_slnPicker is not null) throw new InvalidOperationException("Solution picker is already active");
|
||||||
@@ -109,7 +100,8 @@ public partial class IdeWindow : Control
|
|||||||
{
|
{
|
||||||
GetWindow().Mode = Window.ModeEnum.Maximized;
|
GetWindow().Mode = Window.ModeEnum.Maximized;
|
||||||
}
|
}
|
||||||
_ideRoot = ideRoot;
|
_ideRoot = ideRoot; // This has no DI services, until it is added to the scene tree
|
||||||
|
GetNode<DiAutoload>("/root/DiAutoload").ResetScope();
|
||||||
AddChild(ideRoot);
|
AddChild(ideRoot);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user