File: src\Tools\Shared\SecretsHelpers\UserSecretsCreator.cs
Web Access
Project: src\src\Tools\dotnet-user-secrets\src\dotnet-user-secrets.csproj (dotnet-user-secrets)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Linq;
using System.Xml;
using System.Xml.Linq;
using System.Xml.XPath;
using Microsoft.AspNetCore.Tools;
using Microsoft.Extensions.Tools.Internal;
 
internal static class UserSecretsCreator
{
    public static string CreateUserSecretsId(IReporter reporter, string project, string workingDirectory, string overrideId = null)
    {
        var projectPath = ResolveProjectPath(project, workingDirectory);
 
        // Load the project file as XML
        var projectDocument = XDocument.Load(projectPath, LoadOptions.PreserveWhitespace);
 
        // Accept the `--id` CLI option to the main app
        string newSecretsId = string.IsNullOrWhiteSpace(overrideId)
            ? Guid.NewGuid().ToString()
            : overrideId;
 
        // Confirm secret ID does not contain invalid characters
        if (Path.GetInvalidPathChars().Any(newSecretsId.Contains))
        {
            throw new ArgumentException(SecretsHelpersResources.FormatError_InvalidSecretsId(newSecretsId));
        }
 
        var existingUserSecretsId = projectDocument.XPathSelectElements("//UserSecretsId").FirstOrDefault();
 
        // Check if a UserSecretsId is already set
        if (existingUserSecretsId is not null)
        {
            // Only set the UserSecretsId if the user specified an explicit value
            if (string.IsNullOrWhiteSpace(overrideId))
            {
                reporter.Output(SecretsHelpersResources.FormatMessage_ProjectAlreadyInitialized(projectPath));
                return existingUserSecretsId.Value;
            }
 
            existingUserSecretsId.SetValue(newSecretsId);
        }
        else
        {
            // Find the first non-conditional PropertyGroup
            var propertyGroup = projectDocument.Root.DescendantNodes()
                .FirstOrDefault(node => node is XElement el
                    && el.Name == "PropertyGroup"
                    && el.Attributes().All(attr =>
                        attr.Name != "Condition")) as XElement;
 
            // No valid property group, create a new one
            if (propertyGroup == null)
            {
                propertyGroup = new XElement("PropertyGroup");
                projectDocument.Root.AddFirst(propertyGroup);
            }
 
            // Add UserSecretsId element
            propertyGroup.Add("  ");
            propertyGroup.Add(new XElement("UserSecretsId", newSecretsId));
            propertyGroup.Add($"{Environment.NewLine}  ");
        }
 
        var settings = new XmlWriterSettings
        {
            OmitXmlDeclaration = true,
        };
 
        using var xw = XmlWriter.Create(projectPath, settings);
        projectDocument.Save(xw);
 
        reporter.Output(SecretsHelpersResources.FormatMessage_SetUserSecretsIdForProject(newSecretsId, projectPath));
        return newSecretsId;
    }
 
    private static string ResolveProjectPath(string name, string path)
    {
        var finder = new MsBuildProjectFinder(path);
        return finder.FindMsBuildProject(name);
    }
}