diff --git a/src/SharpIDE.Application/Features/Evaluation/DotnetUserSecretsService.cs b/src/SharpIDE.Application/Features/Evaluation/DotnetUserSecretsService.cs new file mode 100644 index 0000000..1ee0887 --- /dev/null +++ b/src/SharpIDE.Application/Features/Evaluation/DotnetUserSecretsService.cs @@ -0,0 +1,39 @@ +using Ardalis.GuardClauses; +using SharpIDE.Application.Features.SolutionDiscovery.VsPersistence; + +namespace SharpIDE.Application.Features.Evaluation; + +public class DotnetUserSecretsService +{ + public async Task<(Guid, string filePath)> GetOrCreateUserSecretsId(SharpIdeProjectModel projectModel) + { + using var _ = SharpIdeOtel.Source.StartActivity($"{nameof(DotnetUserSecretsService)}.{nameof(GetOrCreateUserSecretsId)}"); + Guard.Against.Null(projectModel, nameof(projectModel)); + + var userSecretsId = ProjectEvaluation.GetOrCreateDotnetUserSecretsId(projectModel); + var userSecretsFilePath = GetUserSecretsFilePath(userSecretsId); + var file = new FileInfo(userSecretsFilePath); + if (file.Exists) + { + return (userSecretsId, userSecretsFilePath); + } + var directory = file.Directory; + if (directory!.Exists is false) + { + directory.Create(); + } + await File.WriteAllTextAsync(userSecretsFilePath, "{}").ConfigureAwait(false); + return (userSecretsId, userSecretsFilePath); + } + + private static string GetUserSecretsFilePath(Guid userSecretsId) + { + var appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); + var userSecretsPath = OperatingSystem.IsWindows() switch + { + true => Path.Combine(appDataPath, "Microsoft", "UserSecrets", userSecretsId.ToString(), "secrets.json"), + false => Path.Combine(appDataPath, ".microsoft", "usersecrets", userSecretsId.ToString(), "secrets.json") + }; + return userSecretsPath; + } +} diff --git a/src/SharpIDE.Application/Features/Evaluation/ProjectEvaluation.cs b/src/SharpIDE.Application/Features/Evaluation/ProjectEvaluation.cs index 585ab90..3693047 100644 --- a/src/SharpIDE.Application/Features/Evaluation/ProjectEvaluation.cs +++ b/src/SharpIDE.Application/Features/Evaluation/ProjectEvaluation.cs @@ -37,4 +37,22 @@ public static class ProjectEvaluation Guard.Against.NullOrWhiteSpace(targetPath, nameof(targetPath)); return targetPath; } + + public static Guid GetOrCreateDotnetUserSecretsId(SharpIdeProjectModel projectModel) + { + Guard.Against.Null(projectModel, nameof(projectModel)); + + var project = _projectCollection.GetLoadedProjects(projectModel.FilePath).Single(); + var projectRootElement = project.Xml; + var userSecretsId = project.GetPropertyValue("UserSecretsId"); + if (string.IsNullOrWhiteSpace(userSecretsId)) + { + var newGuid = Guid.NewGuid(); + var property = projectRootElement.AddProperty("UserSecretsId", newGuid.ToString()); + project.Save(); + return newGuid; + } + return Guid.Parse(userSecretsId); + } + } diff --git a/src/SharpIDE.Godot/DiAutoload.cs b/src/SharpIDE.Godot/DiAutoload.cs index 73e320a..864fc61 100644 --- a/src/SharpIDE.Godot/DiAutoload.cs +++ b/src/SharpIDE.Godot/DiAutoload.cs @@ -5,6 +5,7 @@ using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using SharpIDE.Application.Features.Analysis; using SharpIDE.Application.Features.Build; +using SharpIDE.Application.Features.Evaluation; using SharpIDE.Application.Features.FilePersistence; using SharpIDE.Application.Features.FileWatching; using SharpIDE.Application.Features.Run; @@ -32,6 +33,7 @@ public partial class DiAutoload : Node services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); diff --git a/src/SharpIDE.Godot/Features/SolutionExplorer/ContextMenus/ProjectContextMenu.cs b/src/SharpIDE.Godot/Features/SolutionExplorer/ContextMenus/ProjectContextMenu.cs index bd01cfb..30f7113 100644 --- a/src/SharpIDE.Godot/Features/SolutionExplorer/ContextMenus/ProjectContextMenu.cs +++ b/src/SharpIDE.Godot/Features/SolutionExplorer/ContextMenus/ProjectContextMenu.cs @@ -16,7 +16,8 @@ file enum ProjectContextMenuOptions Build = 2, Rebuild = 3, Clean = 4, - Restore = 5 + Restore = 5, + DotnetUserSecrets = 6, } file enum CreateNewSubmenuOptions @@ -31,6 +32,7 @@ public partial class SolutionExplorerPanel [Inject] private readonly BuildService _buildService = null!; [Inject] private readonly RunService _runService = null!; + [Inject] private readonly DotnetUserSecretsService _dotnetUserSecretsService = null!; private void OpenContextMenuProject(SharpIdeProjectModel project) { @@ -50,6 +52,8 @@ public partial class SolutionExplorerPanel menu.AddItem("Rebuild", (int)ProjectContextMenuOptions.Rebuild); menu.AddItem("Clean", (int)ProjectContextMenuOptions.Clean); menu.AddItem("Restore", (int)ProjectContextMenuOptions.Restore); + menu.AddSeparator(); + menu.AddItem(".NET User Secrets", (int)ProjectContextMenuOptions.DotnetUserSecrets); menu.PopupHide += () => menu.QueueFree(); menu.IdPressed += id => { @@ -78,6 +82,14 @@ public partial class SolutionExplorerPanel { _ = Task.GodotRun(async () => await MsBuildProject(project, BuildType.Restore)); } + else if (actionId is ProjectContextMenuOptions.DotnetUserSecrets) + { + _ = Task.GodotRun(async () => + { + var (userSecretsId, filePath) = await _dotnetUserSecretsService.GetOrCreateUserSecretsId(project); + OS.ShellShowInFileManager(filePath); + }); + } }; var globalMousePosition = GetGlobalMousePosition();