Create an initial implementation of the secret manager for VS (#355)
This commit is contained in:
parent
bd725635c7
commit
4ecabacc76
|
|
@ -1,6 +1,6 @@
|
|||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.27110.0
|
||||
VisualStudioVersion = 15.0.27120.0
|
||||
MinimumVisualStudioVersion = 15.0.26730.03
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{66517987-2A5A-4330-B130-207039378FD4}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
|
|
@ -20,12 +20,14 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
|
|||
build.ps1 = build.ps1
|
||||
build.sh = build.sh
|
||||
CONTRIBUTING.md = CONTRIBUTING.md
|
||||
build\dependencies.props = build\dependencies.props
|
||||
Directory.Build.props = Directory.Build.props
|
||||
Directory.Build.targets = Directory.Build.targets
|
||||
LICENSE.txt = LICENSE.txt
|
||||
NuGet.config = NuGet.config
|
||||
NuGetPackageVerifier.json = NuGetPackageVerifier.json
|
||||
README.md = README.md
|
||||
build\sources.props = build\sources.props
|
||||
version.props = version.props
|
||||
EndProjectSection
|
||||
EndProject
|
||||
|
|
@ -46,46 +48,98 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.Cachin
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.DeveloperCertificates.Tools", "src\Microsoft.AspNetCore.DeveloperCertificates.Tools\Microsoft.AspNetCore.DeveloperCertificates.Tools.csproj", "{4FED5119-EE5C-4753-88A4-D61BDEB4D6C8}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.DeveloperCertificates.XPlat", "src\Microsoft.AspNetCore.DeveloperCertificates.XPlat\Microsoft.AspNetCore.DeveloperCertificates.XPlat.csproj", "{96E71881-1465-44F5-B4B7-DF9B370FFD02}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.VisualStudio.SecretManager", "tooling\Microsoft.VisualStudio.SecretManager\Microsoft.VisualStudio.SecretManager.csproj", "{5E117F2E-7152-447F-BF47-59F759EEF3A7}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tooling", "tooling", "{62826851-7D74-4F1E-B7D1-12553B789CD8}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.VisualStudio.SecretManager.TestExtension", "tooling\Microsoft.VisualStudio.SecretManager.TestExtension\Microsoft.VisualStudio.SecretManager.TestExtension.csproj", "{965F8820-F809-4081-9090-1AEC903F291B}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.DeveloperCertificates.XPlat", "src\Microsoft.AspNetCore.DeveloperCertificates.XPlat\Microsoft.AspNetCore.DeveloperCertificates.XPlat.csproj", "{96E71881-1465-44F5-B4B7-DF9B370FFD02}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
DebugNoVSIX|Any CPU = DebugNoVSIX|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
ReleaseNoVSIX|Any CPU = ReleaseNoVSIX|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{8A8CEABC-AC47-43FF-A5DF-69224F7E1F46}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8A8CEABC-AC47-43FF-A5DF-69224F7E1F46}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8A8CEABC-AC47-43FF-A5DF-69224F7E1F46}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8A8CEABC-AC47-43FF-A5DF-69224F7E1F46}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8A8CEABC-AC47-43FF-A5DF-69224F7E1F46}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8A8CEABC-AC47-43FF-A5DF-69224F7E1F46}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{8A8CEABC-AC47-43FF-A5DF-69224F7E1F46}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8A8CEABC-AC47-43FF-A5DF-69224F7E1F46}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
|
||||
{16BADE2F-1184-4518-8A70-B68A19D0805B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{16BADE2F-1184-4518-8A70-B68A19D0805B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{16BADE2F-1184-4518-8A70-B68A19D0805B}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{16BADE2F-1184-4518-8A70-B68A19D0805B}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
|
||||
{16BADE2F-1184-4518-8A70-B68A19D0805B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{16BADE2F-1184-4518-8A70-B68A19D0805B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{16BADE2F-1184-4518-8A70-B68A19D0805B}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{16BADE2F-1184-4518-8A70-B68A19D0805B}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
|
||||
{8730E848-CA0F-4E0A-9A2F-BC22AD0B2C4E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8730E848-CA0F-4E0A-9A2F-BC22AD0B2C4E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8730E848-CA0F-4E0A-9A2F-BC22AD0B2C4E}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8730E848-CA0F-4E0A-9A2F-BC22AD0B2C4E}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8730E848-CA0F-4E0A-9A2F-BC22AD0B2C4E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8730E848-CA0F-4E0A-9A2F-BC22AD0B2C4E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{8730E848-CA0F-4E0A-9A2F-BC22AD0B2C4E}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8730E848-CA0F-4E0A-9A2F-BC22AD0B2C4E}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
|
||||
{7B331122-83B1-4F08-A119-DC846959844C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{7B331122-83B1-4F08-A119-DC846959844C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7B331122-83B1-4F08-A119-DC846959844C}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{7B331122-83B1-4F08-A119-DC846959844C}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7B331122-83B1-4F08-A119-DC846959844C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7B331122-83B1-4F08-A119-DC846959844C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{7B331122-83B1-4F08-A119-DC846959844C}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7B331122-83B1-4F08-A119-DC846959844C}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
|
||||
{8A2E6961-6B12-4A8E-8215-3E7301D52EAC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8A2E6961-6B12-4A8E-8215-3E7301D52EAC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8A2E6961-6B12-4A8E-8215-3E7301D52EAC}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8A2E6961-6B12-4A8E-8215-3E7301D52EAC}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8A2E6961-6B12-4A8E-8215-3E7301D52EAC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8A2E6961-6B12-4A8E-8215-3E7301D52EAC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{8A2E6961-6B12-4A8E-8215-3E7301D52EAC}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8A2E6961-6B12-4A8E-8215-3E7301D52EAC}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
|
||||
{53F3B53D-303A-4DAA-9C38-4F55195FA5B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{53F3B53D-303A-4DAA-9C38-4F55195FA5B9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{53F3B53D-303A-4DAA-9C38-4F55195FA5B9}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{53F3B53D-303A-4DAA-9C38-4F55195FA5B9}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
|
||||
{53F3B53D-303A-4DAA-9C38-4F55195FA5B9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{53F3B53D-303A-4DAA-9C38-4F55195FA5B9}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{53F3B53D-303A-4DAA-9C38-4F55195FA5B9}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{53F3B53D-303A-4DAA-9C38-4F55195FA5B9}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
|
||||
{4FED5119-EE5C-4753-88A4-D61BDEB4D6C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{4FED5119-EE5C-4753-88A4-D61BDEB4D6C8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{4FED5119-EE5C-4753-88A4-D61BDEB4D6C8}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{4FED5119-EE5C-4753-88A4-D61BDEB4D6C8}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
|
||||
{4FED5119-EE5C-4753-88A4-D61BDEB4D6C8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{4FED5119-EE5C-4753-88A4-D61BDEB4D6C8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{4FED5119-EE5C-4753-88A4-D61BDEB4D6C8}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{4FED5119-EE5C-4753-88A4-D61BDEB4D6C8}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
|
||||
{5E117F2E-7152-447F-BF47-59F759EEF3A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5E117F2E-7152-447F-BF47-59F759EEF3A7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5E117F2E-7152-447F-BF47-59F759EEF3A7}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5E117F2E-7152-447F-BF47-59F759EEF3A7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5E117F2E-7152-447F-BF47-59F759EEF3A7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{5E117F2E-7152-447F-BF47-59F759EEF3A7}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{965F8820-F809-4081-9090-1AEC903F291B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{965F8820-F809-4081-9090-1AEC903F291B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{965F8820-F809-4081-9090-1AEC903F291B}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{965F8820-F809-4081-9090-1AEC903F291B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{965F8820-F809-4081-9090-1AEC903F291B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{965F8820-F809-4081-9090-1AEC903F291B}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{96E71881-1465-44F5-B4B7-DF9B370FFD02}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{96E71881-1465-44F5-B4B7-DF9B370FFD02}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{96E71881-1465-44F5-B4B7-DF9B370FFD02}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{96E71881-1465-44F5-B4B7-DF9B370FFD02}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
|
||||
{96E71881-1465-44F5-B4B7-DF9B370FFD02}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{96E71881-1465-44F5-B4B7-DF9B370FFD02}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{96E71881-1465-44F5-B4B7-DF9B370FFD02}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{96E71881-1465-44F5-B4B7-DF9B370FFD02}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
@ -98,6 +152,8 @@ Global
|
|||
{8A2E6961-6B12-4A8E-8215-3E7301D52EAC} = {F5B382BC-258F-46E1-AC3D-10E5CCD55134}
|
||||
{53F3B53D-303A-4DAA-9C38-4F55195FA5B9} = {66517987-2A5A-4330-B130-207039378FD4}
|
||||
{4FED5119-EE5C-4753-88A4-D61BDEB4D6C8} = {66517987-2A5A-4330-B130-207039378FD4}
|
||||
{5E117F2E-7152-447F-BF47-59F759EEF3A7} = {62826851-7D74-4F1E-B7D1-12553B789CD8}
|
||||
{965F8820-F809-4081-9090-1AEC903F291B} = {62826851-7D74-4F1E-B7D1-12553B789CD8}
|
||||
{96E71881-1465-44F5-B4B7-DF9B370FFD02} = {66517987-2A5A-4330-B130-207039378FD4}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
<!--
|
||||
Workaround for https://github.com/dotnet/project-system/issues/2129 - VS does not support using MSBuild variables for PackageReference items.
|
||||
Using a variable breaks a bunch of stuff, so this file is injected into the VSIX csproj only when building on commandline.
|
||||
-->
|
||||
<Project ToolsVersion="15.0">
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="$(VisualStudio_NewtonsoftJsonPackageVersion)" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
<Project>
|
||||
<PropertyGroup>
|
||||
<BuildVSIX Condition="'$(BuildVSIX)' ==''">true</BuildVSIX>
|
||||
<RestoreDependsOn Condition="'$(OS)'=='Windows_NT' AND '$(BuildVSIX)' == 'true'">$(RestoreDependsOn);RestoreVSIX</RestoreDependsOn>
|
||||
<PackageDependsOn Condition="'$(OS)'=='Windows_NT' AND '$(BuildVSIX)' == 'true'">$(PackageDependsOn);PackageVSIX</PackageDependsOn>
|
||||
<VSIXName>Microsoft.VisualStudio.SecretManager</VSIXName>
|
||||
<VSIXProject>$(RepositoryRoot)tooling\$(VSIXName)\$(VSIXName).csproj</VSIXProject>
|
||||
<VSIXOutputPath>$(BuildDir)$(VSIXName).vsix</VSIXOutputPath>
|
||||
<MSBuildArtifactsDir>$(ArtifactsDir)msbuild\</MSBuildArtifactsDir>
|
||||
</PropertyGroup>
|
||||
|
||||
<Target
|
||||
Name="GenerateVSIX"
|
||||
DependsOnTargets="RestoreVSIX;PackageVSIX"
|
||||
Condition="'$(OS)'=='Windows_NT'" />
|
||||
|
||||
<!--
|
||||
VisualStudioMSBuildx86Path is set by the GetToolsets target in KoreBuild if a version of VS matching the requirements in korebuild.json is found.
|
||||
-->
|
||||
<Target Name="RestoreVSIX" DependsOnTargets="GetToolsets">
|
||||
|
||||
<PropertyGroup>
|
||||
<VSIXResponseFilePath>$(MSBuildArtifactsDir)vsix-restore.rsp</VSIXResponseFilePath>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<MSBuildArguments Remove="@(MSBuildArguments)" />
|
||||
<MSBuildArguments Include="
|
||||
$(VSIXProject);
|
||||
/t:Restore;
|
||||
/m;
|
||||
/v:m;
|
||||
/p:Configuration=$(Configuration);
|
||||
/p:BuildNumber=$(BuildNumber);
|
||||
/p:PackageReferencePropsPath=$(MSBuildThisFileDirectory)VSIX.props;" />
|
||||
<MSBuildArguments Include="/p:DotNetPackageVersionPropsPath=$(DotNetPackageVersionPropsPath)" Condition="'$(DotNetPackageVersionPropsPath)' != ''" />
|
||||
<MSBuildArguments Include="/p:DotNetRestoreSourcePropsPath=$(DotNetRestoreSourcePropsPath)" Condition="'$(DotNetRestoreSourcePropsPath)' != ''" />
|
||||
</ItemGroup>
|
||||
|
||||
<MakeDir Directories="$(MSBuildArtifactsDir)" />
|
||||
|
||||
<WriteLinesToFile
|
||||
File="$(VSIXResponseFilePath)"
|
||||
Lines="@(MSBuildArguments)"
|
||||
Overwrite="true" />
|
||||
|
||||
<Exec Command=""$(VisualStudioMSBuildx86Path)" @"$(VSIXResponseFilePath)""
|
||||
Condition="'$(VisualStudioMSBuildx86Path)' != ''" />
|
||||
</Target>
|
||||
|
||||
<Target Name="PackageVSIX" DependsOnTargets="GetToolsets">
|
||||
|
||||
<Error Text="Could not find a version of Visual Studio that has the Visual Studio SDK installed. This is required to build the SecretManager VSIX."
|
||||
Condition="'$(VisualStudioMSBuildx86Path)' == ''" />
|
||||
|
||||
<PropertyGroup>
|
||||
<VSIXLogFilePath>$(MSBuildArtifactsDir)vsix.log</VSIXLogFilePath>
|
||||
<VSIXResponseFilePath>$(MSBuildArtifactsDir)vsix-build.rsp</VSIXResponseFilePath>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<MSBuildArguments Remove="@(MSBuildArguments)" />
|
||||
<MSBuildArguments Include="
|
||||
$(VSIXProject);
|
||||
/m;
|
||||
/v:M;
|
||||
/fl;
|
||||
/flp:LogFile=$(VSIXLogFilePath);
|
||||
/p:DeployExtension=false;
|
||||
/p:TargetVSIXContainer=$(VSIXOutputPath);
|
||||
/p:Configuration=$(Configuration);
|
||||
/p:PackageReferencePropsPath=$(MSBuildThisFileDirectory)VSIX.props;" />
|
||||
</ItemGroup>
|
||||
|
||||
<MakeDir Directories="$(MSBuildArtifactsDir)" />
|
||||
|
||||
<WriteLinesToFile
|
||||
File="$(VSIXResponseFilePath)"
|
||||
Lines="@(MSBuildArguments)"
|
||||
Overwrite="true" />
|
||||
|
||||
<Exec Command=""$(VisualStudioMSBuildx86Path)" @"$(VSIXResponseFilePath)""
|
||||
Condition="'$(VisualStudioMSBuildx86Path)' != ''" />
|
||||
</Target>
|
||||
|
||||
</Project>
|
||||
|
|
@ -3,17 +3,18 @@
|
|||
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Package Versions">
|
||||
<InternalAspNetCoreSdkPackageVersion>2.1.0-preview1-15549</InternalAspNetCoreSdkPackageVersion>
|
||||
<MicrosoftAspNetCoreCertificatesGenerationSourcesPackageVersion>2.1.0-preview1-27595</MicrosoftAspNetCoreCertificatesGenerationSourcesPackageVersion>
|
||||
<MicrosoftAspNetCoreTestingPackageVersion>2.1.0-preview1-27595</MicrosoftAspNetCoreTestingPackageVersion>
|
||||
<MicrosoftExtensionsCommandLineUtilsSourcesPackageVersion>2.1.0-preview1-27595</MicrosoftExtensionsCommandLineUtilsSourcesPackageVersion>
|
||||
<MicrosoftExtensionsConfigurationUserSecretsPackageVersion>2.1.0-preview1-27595</MicrosoftExtensionsConfigurationUserSecretsPackageVersion>
|
||||
<MicrosoftExtensionsProcessSourcesPackageVersion>2.1.0-preview1-27595</MicrosoftExtensionsProcessSourcesPackageVersion>
|
||||
<InternalAspNetCoreSdkPackageVersion>2.1.0-preview1-15573</InternalAspNetCoreSdkPackageVersion>
|
||||
<MicrosoftAspNetCoreCertificatesGenerationSourcesPackageVersion>2.1.0-preview1-27644</MicrosoftAspNetCoreCertificatesGenerationSourcesPackageVersion>
|
||||
<MicrosoftAspNetCoreTestingPackageVersion>2.1.0-preview1-27644</MicrosoftAspNetCoreTestingPackageVersion>
|
||||
<MicrosoftExtensionsCommandLineUtilsSourcesPackageVersion>2.1.0-preview1-27644</MicrosoftExtensionsCommandLineUtilsSourcesPackageVersion>
|
||||
<MicrosoftExtensionsConfigurationUserSecretsPackageVersion>2.1.0-preview1-27644</MicrosoftExtensionsConfigurationUserSecretsPackageVersion>
|
||||
<MicrosoftExtensionsProcessSourcesPackageVersion>2.1.0-preview1-27644</MicrosoftExtensionsProcessSourcesPackageVersion>
|
||||
<MicrosoftNETCoreApp20PackageVersion>2.0.0</MicrosoftNETCoreApp20PackageVersion>
|
||||
<MicrosoftNETCoreApp21PackageVersion>2.1.0-preview1-25907-02</MicrosoftNETCoreApp21PackageVersion>
|
||||
<MicrosoftNETTestSdkPackageVersion>15.3.0</MicrosoftNETTestSdkPackageVersion>
|
||||
<SystemDataSqlClientPackageVersion>4.4.0</SystemDataSqlClientPackageVersion>
|
||||
<SystemSecurityCryptographyCngPackageVersion>4.4.0</SystemSecurityCryptographyCngPackageVersion>
|
||||
<VisualStudio_NewtonsoftJsonPackageVersion>9.0.1</VisualStudio_NewtonsoftJsonPackageVersion>
|
||||
<XunitPackageVersion>2.3.0</XunitPackageVersion>
|
||||
<XunitRunnerVisualStudioPackageVersion>2.3.0</XunitRunnerVisualStudioPackageVersion>
|
||||
</PropertyGroup>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
<Project>
|
||||
<Import Project="VSIX.targets" />
|
||||
|
||||
<ItemGroup>
|
||||
<Solutions Update="$(RepositoryRoot)DotNetTools.sln">
|
||||
<!-- the 'DebugNoVSIX' and 'ReleaseNoVSIX' configurations exclude the VSIX project, which doesn't build with Microsoft.NET.Sdk yet. -->
|
||||
<AdditionalProperties>Configuration=$(Configuration)NoVSIX</AdditionalProperties>
|
||||
</Solutions>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
<Project>
|
||||
<Project>
|
||||
<Import Project="$(DotNetRestoreSourcePropsPath)" Condition="'$(DotNetRestoreSourcePropsPath)' != ''"/>
|
||||
|
||||
<PropertyGroup Label="RestoreSources">
|
||||
|
|
@ -7,6 +7,7 @@
|
|||
$(RestoreSources);
|
||||
https://dotnet.myget.org/F/aspnetcore-ci-dev/api/v3/index.json;
|
||||
https://dotnet.myget.org/F/aspnetcore-tools/api/v3/index.json;
|
||||
https://vside.myget.org/F/vssdk/api/v3/index.json;
|
||||
</RestoreSources>
|
||||
<RestoreSources Condition="'$(DotNetBuildOffline)' != 'true'">
|
||||
$(RestoreSources);
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
version:2.1.0-preview1-15549
|
||||
commithash:f570e08585fec510dd60cd4bfe8795388b757a95
|
||||
version:2.1.0-preview1-15573
|
||||
commithash:82cb53a8578610baf96ef33142797c68bae68c81
|
||||
|
|
|
|||
|
|
@ -1,4 +1,16 @@
|
|||
{
|
||||
"$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/dev/tools/korebuild.schema.json",
|
||||
"channel": "dev"
|
||||
"channel": "dev",
|
||||
"toolsets": {
|
||||
"visualstudio": {
|
||||
"required": [
|
||||
"windows"
|
||||
],
|
||||
"includePrerelease": true,
|
||||
"minVersion": "15.4",
|
||||
"requiredWorkloads": [
|
||||
"Microsoft.VisualStudio.Component.VSSDK"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -0,0 +1,149 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<MinimumVisualStudioVersion>15.0</MinimumVisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
<ImportDirectoryBuildProps>False</ImportDirectoryBuildProps>
|
||||
<ImportDirectoryBuildTargets>False</ImportDirectoryBuildTargets>
|
||||
<GenerateUserSecretsAttribute>False</GenerateUserSecretsAttribute>
|
||||
<UseCodebase>True</UseCodebase>
|
||||
<SignAssembly>True</SignAssembly>
|
||||
<AssemblyOriginatorKeyFile>..\..\build\Key.snk</AssemblyOriginatorKeyFile>
|
||||
<TreatWarningsAsErrors>True</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
<Import Project="..\..\version.props" />
|
||||
<Import Project="..\..\build\dependencies.props" />
|
||||
<Import Project="..\..\build\sources.props" />
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectTypeGuids>{82b43b9b-a64c-4715-b499-d71e9ca2bd60};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<ProjectGuid>{965F8820-F809-4081-9090-1AEC903F291B}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Microsoft.VisualStudio.SecretManager.TestExtension</RootNamespace>
|
||||
<AssemblyName>Microsoft.VisualStudio.SecretManager.TestExtension</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||
<GeneratePkgDefFile>true</GeneratePkgDefFile>
|
||||
<IncludeAssemblyInVSIXContainer>true</IncludeAssemblyInVSIXContainer>
|
||||
<IncludeDebugSymbolsInVSIXContainer>true</IncludeDebugSymbolsInVSIXContainer>
|
||||
<IncludeDebugSymbolsInLocalVSIXDeployment>true</IncludeDebugSymbolsInLocalVSIXDeployment>
|
||||
<CopyBuildOutputToOutputDirectory>true</CopyBuildOutputToOutputDirectory>
|
||||
<CopyOutputSymbolsToOutputDirectory>false</CopyOutputSymbolsToOutputDirectory>
|
||||
<StartAction>Program</StartAction>
|
||||
<StartProgram Condition="'$(DevEnvDir)' != ''">$(DevEnvDir)devenv.exe</StartProgram>
|
||||
<StartArguments>/rootsuffix Exp</StartArguments>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="NotifyPropertyChanged.cs" />
|
||||
<Compile Include="ProjectViewModel.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="RelayCommand.cs" />
|
||||
<Compile Include="SecretManagerTestWindow.cs" />
|
||||
<Compile Include="SecretManagerTestCommand.cs" />
|
||||
<Compile Include="SecretManagerTestControl.xaml.cs">
|
||||
<DependentUpon>SecretManagerTestControl.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="SecretManagerTestPackage.cs" />
|
||||
<Compile Include="SecretManagerViewModel.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="source.extension.vsixmanifest">
|
||||
<SubType>Designer</SubType>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="app.config" />
|
||||
<None Include="Key.snk" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Include="SecretManagerTestControl.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="PresentationCore" />
|
||||
<Reference Include="PresentationFramework" />
|
||||
<Reference Include="stdole, Version=7.0.3300.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<EmbedInteropTypes>False</EmbedInteropTypes>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.ComponentModel.Composition" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Design" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.Xaml" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="WindowsBase" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.VisualStudio.ComponentModelHost" Version="15.0.26606" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.ProjectSystem.Analyzers" Version="15.3.224" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.ProjectSystem.SDK.Tools" Version="15.3.224" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.ProjectSystem.SDK" Version="15.3.224" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.ProjectSystem" Version="15.3.224" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Shell.Interop">
|
||||
<Version>7.10.6071</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.VisualStudio.Shell.Interop.10.0" Version="10.0.30319" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Shell.15.0" Version="15.0.26606" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Shell.Embeddable" Version="15.6.27002-vsuvscore" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Shell.Interop.11.0">
|
||||
<Version>11.0.61030</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.VisualStudio.Shell.Interop.12.0">
|
||||
<Version>12.0.30110</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.VisualStudio.Shell.Interop.15.3.DesignTime">
|
||||
<Version>15.0.26606</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.VisualStudio.Shell.Interop.8.0">
|
||||
<Version>8.0.50727</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.VisualStudio.Shell.Interop.9.0">
|
||||
<Version>9.0.30729</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.VSSDK.BuildTools" Version="15.1.192" />
|
||||
<PackageReference Include="System.ValueTuple">
|
||||
<Version>4.4.0</Version>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Resources\SecretManagerTestCommand.png" />
|
||||
<Content Include="Resources\SecretManagerTestPackage.ico" />
|
||||
<VSCTCompile Include="SecretManagerTestPackage.vsct">
|
||||
<ResourceName>Menus.ctmenu</ResourceName>
|
||||
</VSCTCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="VSPackage.resx">
|
||||
<MergeWithCTO>true</MergeWithCTO>
|
||||
<ManifestResourceName>VSPackage</ManifestResourceName>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<Target Name="GetBuildVersion" Outputs="$(VsixVersion)" />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="$(VSToolsPath)\VSSDK\Microsoft.VsSDK.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Microsoft.VisualStudio.SecretManager.TestExtension
|
||||
{
|
||||
public abstract class NotifyPropertyChanged : INotifyPropertyChanged
|
||||
{
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.IO;
|
||||
using Microsoft.VisualStudio.ProjectSystem;
|
||||
|
||||
namespace Microsoft.VisualStudio.SecretManager.TestExtension
|
||||
{
|
||||
public class ProjectViewModel : NotifyPropertyChanged
|
||||
{
|
||||
public ProjectViewModel(UnconfiguredProject project)
|
||||
{
|
||||
Project = project;
|
||||
}
|
||||
|
||||
internal UnconfiguredProject Project { get; }
|
||||
|
||||
public string ProjectName => Path.GetFileNameWithoutExtension(Project.FullPath);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("Microsoft.VisualStudio.SecretManager.TestExtension")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("Microsoft.VisualStudio.SecretManager.TestExtension")]
|
||||
[assembly: AssemblyCopyright("")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace Microsoft.VisualStudio.SecretManager.TestExtension
|
||||
{
|
||||
public class RelayCommand<T> : ICommand
|
||||
{
|
||||
readonly Action<T> _execute = null;
|
||||
readonly Predicate<T> _canExecute = null;
|
||||
|
||||
public RelayCommand(Action<T> execute)
|
||||
: this(execute, null)
|
||||
{
|
||||
}
|
||||
|
||||
public RelayCommand(Action<T> execute, Predicate<T> canExecute)
|
||||
{
|
||||
if (execute == null)
|
||||
throw new ArgumentNullException("execute");
|
||||
|
||||
_execute = execute;
|
||||
_canExecute = canExecute;
|
||||
}
|
||||
|
||||
public bool CanExecute(object parameter)
|
||||
{
|
||||
return _canExecute == null ? true : _canExecute((T)parameter);
|
||||
}
|
||||
|
||||
public event EventHandler CanExecuteChanged
|
||||
{
|
||||
add { CommandManager.RequerySuggested += value; }
|
||||
remove { CommandManager.RequerySuggested -= value; }
|
||||
}
|
||||
|
||||
public void Execute(object parameter)
|
||||
{
|
||||
_execute((T)parameter);
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 418 KiB |
|
|
@ -0,0 +1,100 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.ComponentModel.Design;
|
||||
using Microsoft.VisualStudio.Shell;
|
||||
using Microsoft.VisualStudio.Shell.Interop;
|
||||
|
||||
namespace Microsoft.VisualStudio.SecretManager.TestExtension
|
||||
{
|
||||
internal sealed class SecretManagerTestCommand
|
||||
{
|
||||
/// <summary>
|
||||
/// Command ID.
|
||||
/// </summary>
|
||||
public const int CommandId = 0x0100;
|
||||
|
||||
/// <summary>
|
||||
/// Command menu group (command set GUID).
|
||||
/// </summary>
|
||||
public static readonly Guid CommandSet = new Guid("e415a3f4-f2a8-4834-b7f7-f89844b2505c");
|
||||
|
||||
/// <summary>
|
||||
/// VS Package that provides this command, not null.
|
||||
/// </summary>
|
||||
private readonly Package package;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SecretManagerTestCommand"/> class.
|
||||
/// Adds our command handlers for menu (commands must exist in the command table file)
|
||||
/// </summary>
|
||||
/// <param name="package">Owner package, not null.</param>
|
||||
private SecretManagerTestCommand(Package package)
|
||||
{
|
||||
if (package == null)
|
||||
{
|
||||
throw new ArgumentNullException("package");
|
||||
}
|
||||
|
||||
this.package = package;
|
||||
|
||||
OleMenuCommandService commandService = this.ServiceProvider.GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
|
||||
if (commandService != null)
|
||||
{
|
||||
var menuCommandID = new CommandID(CommandSet, CommandId);
|
||||
var menuItem = new MenuCommand(this.ShowToolWindow, menuCommandID);
|
||||
commandService.AddCommand(menuItem);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the instance of the command.
|
||||
/// </summary>
|
||||
public static SecretManagerTestCommand Instance
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the service provider from the owner package.
|
||||
/// </summary>
|
||||
private IServiceProvider ServiceProvider
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.package;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the singleton instance of the command.
|
||||
/// </summary>
|
||||
/// <param name="package">Owner package, not null.</param>
|
||||
public static void Initialize(Package package)
|
||||
{
|
||||
Instance = new SecretManagerTestCommand(package);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shows the tool window when the menu item is clicked.
|
||||
/// </summary>
|
||||
/// <param name="sender">The event sender.</param>
|
||||
/// <param name="e">The event args.</param>
|
||||
private void ShowToolWindow(object sender, EventArgs e)
|
||||
{
|
||||
// Get the instance number 0 of this tool window. This window is single instance so this instance
|
||||
// is actually the only one.
|
||||
// The last flag is set to true so that if the tool window does not exists it will be created.
|
||||
ToolWindowPane window = this.package.FindToolWindow(typeof(SecretManagerTestWindow), 0, true);
|
||||
if ((null == window) || (null == window.Frame))
|
||||
{
|
||||
throw new NotSupportedException("Cannot create tool window");
|
||||
}
|
||||
|
||||
IVsWindowFrame windowFrame = (IVsWindowFrame)window.Frame;
|
||||
Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(windowFrame.Show());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
<UserControl
|
||||
x:Class="Microsoft.VisualStudio.SecretManager.TestExtension.SecretManagerTestControl"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
Background="{DynamicResource VsBrush.Window}"
|
||||
Foreground="{DynamicResource VsBrush.WindowText}"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="300"
|
||||
d:DesignWidth="300">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition
|
||||
Width="Auto" />
|
||||
<ColumnDefinition
|
||||
Width="*" />
|
||||
<ColumnDefinition
|
||||
Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition
|
||||
Height="Auto" />
|
||||
<RowDefinition
|
||||
Height="Auto" />
|
||||
<RowDefinition
|
||||
Height="*" />
|
||||
<RowDefinition
|
||||
Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<StackPanel
|
||||
Grid.ColumnSpan="3"
|
||||
Grid.Row="0"
|
||||
Visibility="{Binding ErrorVisibility}">
|
||||
<Label Content="{Binding Error}" HorizontalContentAlignment="Center" Foreground="Red"/>
|
||||
</StackPanel>
|
||||
|
||||
<Label
|
||||
Grid.Column="0"
|
||||
Grid.Row="1"
|
||||
Content="Select Project"
|
||||
Margin="5"
|
||||
Width="Auto" />
|
||||
|
||||
<ComboBox
|
||||
Grid.Column="1"
|
||||
Grid.Row="1"
|
||||
ItemsSource="{Binding Projects}"
|
||||
SelectedItem="{Binding SelectedProject}"
|
||||
DisplayMemberPath="ProjectName"
|
||||
Margin="5"
|
||||
HorizontalAlignment="Stretch" />
|
||||
|
||||
<Button
|
||||
Grid.Column="2"
|
||||
Grid.Row="1"
|
||||
Margin="5"
|
||||
Content="Refresh"
|
||||
Command="{Binding RefreshCommand}" />
|
||||
|
||||
<ListView
|
||||
Grid.ColumnSpan="3"
|
||||
Grid.Row="2"
|
||||
ItemsSource="{Binding Secrets}"
|
||||
IsEnabled="{Binding IsLoaded}">
|
||||
<ListView.View>
|
||||
<GridView>
|
||||
<GridViewColumn
|
||||
Header="Key"
|
||||
DisplayMemberBinding="{Binding Key}" />
|
||||
<GridViewColumn
|
||||
Header="Value"
|
||||
DisplayMemberBinding="{Binding Value}" />
|
||||
</GridView>
|
||||
</ListView.View>
|
||||
</ListView>
|
||||
|
||||
<StackPanel
|
||||
Margin="4"
|
||||
Orientation="Horizontal"
|
||||
Grid.Row="3">
|
||||
<Button Padding="10,3" Command="{Binding AddCommand}">Add random value</Button>
|
||||
<Button Padding="10,3" Margin="5,0,0,0" Command="{Binding SaveCommand}">Save</Button>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
namespace Microsoft.VisualStudio.SecretManager.TestExtension
|
||||
{
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
/// <summary>
|
||||
/// Interaction logic for SecretManagerTestControl.
|
||||
/// </summary>
|
||||
public partial class SecretManagerTestControl : UserControl
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SecretManagerTestControl"/> class.
|
||||
/// </summary>
|
||||
public SecretManagerTestControl()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles click on the button by displaying a message box.
|
||||
/// </summary>
|
||||
/// <param name="sender">The event sender.</param>
|
||||
/// <param name="e">The event args.</param>
|
||||
[SuppressMessage("Microsoft.Globalization", "CA1300:SpecifyMessageBoxOptions", Justification = "Sample code")]
|
||||
[SuppressMessage("StyleCop.CSharp.NamingRules", "SA1300:ElementMustBeginWithUpperCaseLetter", Justification = "Default event handler naming pattern")]
|
||||
private void button1_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
MessageBox.Show(
|
||||
string.Format(System.Globalization.CultureInfo.CurrentUICulture, "Invoked '{0}'", this.ToString()),
|
||||
"SecretManagerTest");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
using Microsoft.VisualStudio.Shell;
|
||||
|
||||
namespace Microsoft.VisualStudio.SecretManager.TestExtension
|
||||
{
|
||||
[PackageRegistration(UseManagedResourcesOnly = true)]
|
||||
[InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)] // Info on this package for Help/About
|
||||
[ProvideMenuResource("Menus.ctmenu", 1)]
|
||||
[ProvideToolWindow(typeof(SecretManagerTestWindow))]
|
||||
[Guid(SecretManagerTestPackage.PackageGuidString)]
|
||||
[SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1650:ElementDocumentationMustBeSpelledCorrectly", Justification = "pkgdef, VS and vsixmanifest are valid VS terms")]
|
||||
public sealed class SecretManagerTestPackage : Package
|
||||
{
|
||||
public const string PackageGuidString = "7b771e3e-f599-4fde-95a9-e35019e705f7";
|
||||
|
||||
protected override void Initialize()
|
||||
{
|
||||
SecretManagerTestCommand.Initialize(this);
|
||||
base.Initialize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<CommandTable xmlns="http://schemas.microsoft.com/VisualStudio/2005-10-18/CommandTable" xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
|
||||
<!-- This is the file that defines the actual layout and type of the commands.
|
||||
It is divided in different sections (e.g. command definition, command
|
||||
placement, ...), with each defining a specific set of properties.
|
||||
See the comment before each section for more details about how to
|
||||
use it. -->
|
||||
|
||||
<!-- The VSCT compiler (the tool that translates this file into the binary
|
||||
format that VisualStudio will consume) has the ability to run a preprocessor
|
||||
on the vsct file; this preprocessor is (usually) the C++ preprocessor, so
|
||||
it is possible to define includes and macros with the same syntax used
|
||||
in C++ files. Using this ability of the compiler here, we include some files
|
||||
defining some of the constants that we will use inside the file. -->
|
||||
|
||||
<!--This is the file that defines the IDs for all the commands exposed by VisualStudio. -->
|
||||
<Extern href="stdidcmd.h"/>
|
||||
|
||||
<!--This header contains the command ids for the menus provided by the shell. -->
|
||||
<Extern href="vsshlids.h"/>
|
||||
|
||||
<!--The Commands section is where commands, menus, and menu groups are defined.
|
||||
This section uses a Guid to identify the package that provides the command defined inside it. -->
|
||||
<Commands package="guidSecretManagerTestPackage">
|
||||
<!-- Inside this section we have different sub-sections: one for the menus, another
|
||||
for the menu groups, one for the buttons (the actual commands), one for the combos
|
||||
and the last one for the bitmaps used. Each element is identified by a command id that
|
||||
is a unique pair of guid and numeric identifier; the guid part of the identifier is usually
|
||||
called "command set" and is used to group different command inside a logically related
|
||||
group; your package should define its own command set in order to avoid collisions
|
||||
with command ids defined by other packages. -->
|
||||
|
||||
<!--Buttons section. -->
|
||||
<!--This section defines the elements the user can interact with, like a menu command or a button
|
||||
or combo box in a toolbar. -->
|
||||
<Buttons>
|
||||
<!--To define a menu group you have to specify its ID, the parent menu and its display priority.
|
||||
The command is visible and enabled by default. If you need to change the visibility, status, etc, you can use
|
||||
the CommandFlag node.
|
||||
You can add more than one CommandFlag node e.g.:
|
||||
<CommandFlag>DefaultInvisible</CommandFlag>
|
||||
<CommandFlag>DynamicVisibility</CommandFlag>
|
||||
If you do not want an image next to your command, remove the Icon node /> -->
|
||||
<Button guid="guidSecretManagerTestPackageCmdSet" id="SecretManagerTestCommandId" priority="0x0100" type="Button">
|
||||
<Parent guid="guidSHLMainMenu" id="IDG_VS_WNDO_OTRWNDWS1"/>
|
||||
<Icon guid="guidImages" id="bmpPic1" />
|
||||
<Strings>
|
||||
<ButtonText>SecretManager Test</ButtonText>
|
||||
</Strings>
|
||||
</Button>
|
||||
</Buttons>
|
||||
|
||||
<!--The bitmaps section is used to define the bitmaps that are used for the commands.-->
|
||||
<Bitmaps>
|
||||
<!-- The bitmap id is defined in a way that is a little bit different from the others:
|
||||
the declaration starts with a guid for the bitmap strip, then there is the resource id of the
|
||||
bitmap strip containing the bitmaps and then there are the numeric ids of the elements used
|
||||
inside a button definition. An important aspect of this declaration is that the element id
|
||||
must be the actual index (1-based) of the bitmap inside the bitmap strip. -->
|
||||
<Bitmap guid="guidImages" href="Resources\SecretManagerTestCommand.png" usedList="bmpPic1, bmpPic2, bmpPicSearch, bmpPicX, bmpPicArrows, bmpPicStrikethrough"/>
|
||||
</Bitmaps>
|
||||
</Commands>
|
||||
|
||||
<Symbols>
|
||||
<!-- This is the package guid. -->
|
||||
<GuidSymbol name="guidSecretManagerTestPackage" value="{7b771e3e-f599-4fde-95a9-e35019e705f7}" />
|
||||
|
||||
<!-- This is the guid used to group the menu commands together -->
|
||||
<GuidSymbol name="guidSecretManagerTestPackageCmdSet" value="{e415a3f4-f2a8-4834-b7f7-f89844b2505c}">
|
||||
<IDSymbol name="SecretManagerTestCommandId" value="0x0100" />
|
||||
</GuidSymbol>
|
||||
|
||||
<GuidSymbol name="guidImages" value="{ab6e0ec7-5f1f-4134-a2b5-28e528fac523}" >
|
||||
<IDSymbol name="bmpPic1" value="1" />
|
||||
<IDSymbol name="bmpPic2" value="2" />
|
||||
<IDSymbol name="bmpPicSearch" value="3" />
|
||||
<IDSymbol name="bmpPicX" value="4" />
|
||||
<IDSymbol name="bmpPicArrows" value="5" />
|
||||
<IDSymbol name="bmpPicStrikethrough" value="6" />
|
||||
</GuidSymbol>
|
||||
</Symbols>
|
||||
</CommandTable>
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using Microsoft.VisualStudio.ComponentModelHost;
|
||||
using Microsoft.VisualStudio.ProjectSystem;
|
||||
using Microsoft.VisualStudio.Shell;
|
||||
|
||||
namespace Microsoft.VisualStudio.SecretManager.TestExtension
|
||||
{
|
||||
[Guid("6afffd63-17b6-4ef2-b515-fee22d767631")]
|
||||
public class SecretManagerTestWindow : ToolWindowPane
|
||||
{
|
||||
public SecretManagerTestWindow()
|
||||
: base(null)
|
||||
{
|
||||
this.Caption = "SecretManager Test Window";
|
||||
this.Content = new SecretManagerTestControl();
|
||||
}
|
||||
|
||||
protected override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
var component = (IComponentModel)GetService(typeof(SComponentModel));
|
||||
var projectService = component.GetService<IProjectServiceAccessor>().GetProjectService();
|
||||
((SecretManagerTestControl)Content).DataContext = new SecretManagerViewModel(projectService);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,214 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using Microsoft.VisualStudio.ProjectSystem;
|
||||
using Microsoft.VisualStudio.Shell;
|
||||
using Microsoft.VisualStudio.Shell.Interop;
|
||||
using Microsoft.VisualStudio.Threading;
|
||||
using IOleServiceProvider = Microsoft.VisualStudio.OLE.Interop.IServiceProvider;
|
||||
using Task = System.Threading.Tasks.Task;
|
||||
|
||||
namespace Microsoft.VisualStudio.SecretManager.TestExtension
|
||||
{
|
||||
public class SecretManagerViewModel : NotifyPropertyChanged
|
||||
{
|
||||
private readonly IProjectService _projectService;
|
||||
private readonly Random _rand;
|
||||
private string _error;
|
||||
private bool _isLoaded;
|
||||
private ProjectViewModel _selectedProject;
|
||||
|
||||
public SecretManagerViewModel(IProjectService projectService)
|
||||
{
|
||||
_projectService = projectService;
|
||||
|
||||
RefreshCommand = new RelayCommand<object>(Refresh, RefreshIsEnabled);
|
||||
AddCommand = new RelayCommand<object>(Add, IsProjectLoaded);
|
||||
SaveCommand = new RelayCommand<object>(Save, IsProjectLoaded);
|
||||
Refresh(null);
|
||||
_rand = new Random();
|
||||
}
|
||||
|
||||
public RelayCommand<object> RefreshCommand { get; }
|
||||
|
||||
public RelayCommand<object> AddCommand { get; }
|
||||
public RelayCommand<object> SaveCommand { get; }
|
||||
|
||||
public ObservableCollection<ProjectViewModel> Projects { get; } = new ObservableCollection<ProjectViewModel>();
|
||||
|
||||
public ProjectViewModel SelectedProject
|
||||
{
|
||||
get => _selectedProject;
|
||||
set
|
||||
{
|
||||
if (value == _selectedProject)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_selectedProject = value;
|
||||
OnSelectedProjectChanged();
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsLoaded
|
||||
{
|
||||
get => _isLoaded;
|
||||
set
|
||||
{
|
||||
if (value == _isLoaded)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_isLoaded = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public string Error
|
||||
{
|
||||
get => _error;
|
||||
set
|
||||
{
|
||||
if (value == _error)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_error = value;
|
||||
OnPropertyChanged();
|
||||
OnPropertyChanged(nameof(ErrorVisibility));
|
||||
}
|
||||
}
|
||||
|
||||
public Visibility ErrorVisibility => Error == null ? Visibility.Collapsed : Visibility.Visible;
|
||||
|
||||
public ObservableCollection<KeyValuePair<string, string>> Secrets { get; } = new ObservableCollection<KeyValuePair<string, string>>();
|
||||
|
||||
private bool RefreshIsEnabled(object obj) => IsLoaded || SelectedProject == null;
|
||||
|
||||
private void Refresh(object obj)
|
||||
{
|
||||
Projects.Clear();
|
||||
|
||||
foreach (var project in _projectService.LoadedUnconfiguredProjects)
|
||||
{
|
||||
Projects.Add(new ProjectViewModel(project));
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsProjectLoaded(object obj) => IsLoaded && SelectedProject != null;
|
||||
|
||||
private void Add(object obj)
|
||||
{
|
||||
Secrets.Add(new KeyValuePair<string, string>("NewKey" + _rand.Next(10_000), "My new totally random and secret test value"));
|
||||
}
|
||||
|
||||
private async void Save(object obj)
|
||||
{
|
||||
Exception exception;
|
||||
|
||||
try
|
||||
{
|
||||
IOleServiceProvider oleServices;
|
||||
var project = (IVsProject)_selectedProject.Project.Services.HostObject;
|
||||
Marshal.ThrowExceptionForHR(project.GetItemContext((uint)VSConstants.VSITEMID.Root, out oleServices));
|
||||
var services = new ServiceProvider(oleServices);
|
||||
|
||||
var projectSecrets = (IVsProjectSecrets)services.GetService(typeof(SVsProjectLocalSecrets));
|
||||
await TaskScheduler.Default;
|
||||
|
||||
if (projectSecrets == null)
|
||||
{
|
||||
exception = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var secret in Secrets)
|
||||
{
|
||||
await projectSecrets.SetSecretAsync(secret.Key, secret.Value).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
exception = null;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
exception = ex;
|
||||
}
|
||||
|
||||
if (exception != null)
|
||||
{
|
||||
Error = exception.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
private async void OnSelectedProjectChanged()
|
||||
{
|
||||
Secrets.Clear();
|
||||
IsLoaded = false;
|
||||
|
||||
if (_selectedProject == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
KeyValuePair<string, string>[] results;
|
||||
Exception exception;
|
||||
|
||||
try
|
||||
{
|
||||
IOleServiceProvider oleServices;
|
||||
var project = (IVsProject)_selectedProject.Project.Services.HostObject;
|
||||
Marshal.ThrowExceptionForHR(project.GetItemContext((uint)VSConstants.VSITEMID.Root, out oleServices));
|
||||
var services = new ServiceProvider(oleServices);
|
||||
|
||||
var projectSecrets = (IVsProjectSecrets)services.GetService(typeof(SVsProjectLocalSecrets));
|
||||
await TaskScheduler.Default;
|
||||
|
||||
if (projectSecrets == null)
|
||||
{
|
||||
results = null;
|
||||
exception = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
var secrets = await projectSecrets.GetSecretsAsync().ConfigureAwait(false);
|
||||
|
||||
results = secrets.ToArray();
|
||||
exception = null;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
results = null;
|
||||
exception = ex;
|
||||
}
|
||||
|
||||
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
|
||||
|
||||
if (exception != null)
|
||||
{
|
||||
Error = exception.ToString();
|
||||
}
|
||||
else if (results != null)
|
||||
{
|
||||
for (var i = 0; i < results.Length; i++)
|
||||
{
|
||||
Secrets.Add(results[i]);
|
||||
}
|
||||
}
|
||||
|
||||
IsLoaded = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,140 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
VS SDK Notes: This resx file contains the resources that will be consumed from your package by Visual Studio.
|
||||
For example, Visual Studio will attempt to load resource '400' from this resource stream when it needs to
|
||||
load your package's icon. Because Visual Studio will always look in the VSPackage.resources stream first for
|
||||
resources it needs, you should put additional resources that Visual Studio will load directly into this resx
|
||||
file.
|
||||
|
||||
Resources that you would like to access directly from your package in a strong-typed fashion should be stored
|
||||
in Resources.resx or another resx file.
|
||||
-->
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="110" xml:space="preserve">
|
||||
<value>SecretManagerTest Extension</value>
|
||||
</data>
|
||||
<data name="112" xml:space="preserve">
|
||||
<value>SecretManagerTest Visual Studio Extension Detailed Info</value>
|
||||
</data>
|
||||
<data name="400" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>Resources\SecretManagerTestPackage.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-1.2.2.0" newVersion="1.2.2.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.VisualStudio.Validation" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-15.3.0.0" newVersion="15.3.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Composition.AttributedModel" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-1.0.32.0" newVersion="1.0.32.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Threading.Tasks.Dataflow" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.6.2.0" newVersion="4.6.2.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Composition.Runtime" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-1.0.32.0" newVersion="1.0.32.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
</configuration>
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011" xmlns:d="http://schemas.microsoft.com/developer/vsx-schema-design/2011">
|
||||
<Metadata>
|
||||
<Identity Id="Microsoft.VisualStudio.SecretManager.TestExtension" Version="|%CurrentProject%;GetBuildVersion|" Language="en-US" Publisher="Microsoft" />
|
||||
<DisplayName>Microsoft.VisualStudio.SecretManager.TestExtension</DisplayName>
|
||||
<Description xml:space="preserve">A test extension for Microsoft.VisualStudio.TestExtension</Description>
|
||||
</Metadata>
|
||||
<Installation>
|
||||
<InstallationTarget Id="Microsoft.VisualStudio.Community" Version="[15.0]" />
|
||||
</Installation>
|
||||
<Dependencies>
|
||||
<Dependency Id="Microsoft.Framework.NDP" DisplayName="Microsoft .NET Framework" d:Source="Manual" Version="[4.5,)" />
|
||||
<Dependency Id="Microsoft.VisualStudio.MPF.15.0" DisplayName="Visual Studio MPF 15.0" d:Source="Installed" Version="[15.0]" />
|
||||
</Dependencies>
|
||||
<Prerequisites>
|
||||
<Prerequisite Id="Microsoft.VisualStudio.Component.CoreEditor" Version="[15.0,16.0)" DisplayName="Visual Studio core editor" />
|
||||
</Prerequisites>
|
||||
<Assets>
|
||||
<Asset Type="Microsoft.VisualStudio.VsPackage" d:Source="Project" d:ProjectName="%CurrentProject%" Path="|%CurrentProject%;PkgdefProjectOutputGroup|" />
|
||||
</Assets>
|
||||
</PackageManifest>
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<MinimumVisualStudioVersion>15.0</MinimumVisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
<ImportDirectoryBuildProps>False</ImportDirectoryBuildProps>
|
||||
<ImportDirectoryBuildTargets>False</ImportDirectoryBuildTargets>
|
||||
<GenerateUserSecretsAttribute>False</GenerateUserSecretsAttribute>
|
||||
<UseCodebase>True</UseCodebase>
|
||||
<SignAssembly>True</SignAssembly>
|
||||
<AssemblyOriginatorKeyFile>..\..\build\Key.snk</AssemblyOriginatorKeyFile>
|
||||
<TreatWarningsAsErrors>True</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
<Import Project="..\..\version.props" />
|
||||
<Import Project="..\..\build\dependencies.props" />
|
||||
<Import Project="..\..\build\sources.props" />
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectTypeGuids>{82b43b9b-a64c-4715-b499-d71e9ca2bd60};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<ProjectGuid>{5E117F2E-7152-447F-BF47-59F759EEF3A7}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Microsoft.VisualStudio.SecretManager</RootNamespace>
|
||||
<AssemblyName>Microsoft.VisualStudio.SecretManager</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||
<GeneratePkgDefFile>true</GeneratePkgDefFile>
|
||||
<IncludeAssemblyInVSIXContainer>true</IncludeAssemblyInVSIXContainer>
|
||||
<IncludeDebugSymbolsInVSIXContainer>true</IncludeDebugSymbolsInVSIXContainer>
|
||||
<IncludeDebugSymbolsInLocalVSIXDeployment>true</IncludeDebugSymbolsInLocalVSIXDeployment>
|
||||
<CopyBuildOutputToOutputDirectory>true</CopyBuildOutputToOutputDirectory>
|
||||
<CopyOutputSymbolsToOutputDirectory>false</CopyOutputSymbolsToOutputDirectory>
|
||||
<StartAction>Program</StartAction>
|
||||
<StartProgram Condition="'$(DevEnvDir)' != ''">$(DevEnvDir)devenv.exe</StartProgram>
|
||||
<StartArguments>/rootsuffix Exp</StartArguments>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>TRACE;DEBUG;EXTENSION_DEVELOPER_MODE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<LangVersion>latest</LangVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<LangVersion>latest</LangVersion>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="ProjectLocalSecretsManager.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Resources.Designer.cs" />
|
||||
<Compile Include="SecretManagerFactory.cs" />
|
||||
<Compile Include="SecretStore.cs" />
|
||||
<Compile Include="Sources\ConfigurationPath.cs" />
|
||||
<Compile Include="Sources\JsonConfigurationFileParser.cs" />
|
||||
<Compile Include="Sources\PathHelper.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="source.extension.vsixmanifest">
|
||||
<SubType>Designer</SubType>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.VisualStudio.ComponentModelHost" Version="15.0.26606" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.ProjectSystem.Analyzers" Version="15.3.224" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.ProjectSystem.SDK.Tools" Version="15.3.224" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.ProjectSystem.SDK" Version="15.3.224" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.ProjectSystem" Version="15.3.224" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Shell.15.0" Version="15.0.26606" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Shell.Embeddable" Version="15.6.27002-vsuvscore" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Text.Data" Version="15.0.26606" />
|
||||
<PackageReference Include="Microsoft.VSSDK.BuildTools" Version="15.1.192" />
|
||||
</ItemGroup>
|
||||
<!--
|
||||
Begin workaround for https://github.com/dotnet/project-system/issues/2129
|
||||
VS does not support using MSBuild variables for PackageReference items
|
||||
-->
|
||||
<ItemGroup Condition="'$(PackageReferencePropsPath)' == ''">
|
||||
<PackageReference Include="Newtonsoft.Json" Version="9.0.1" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(PackageReferencePropsPath)" Condition="'$(PackageReferencePropsPath)' != ''" />
|
||||
<!-- End workaround -->
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.ComponentModel.Composition" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Resources.resx">
|
||||
<SubType>Designer</SubType>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<Target Name="GetBuildVersion" Outputs="$(VsixVersion)" />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="$(VSToolsPath)\VSSDK\Microsoft.VsSDK.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,148 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.VisualStudio.ProjectSystem.Properties;
|
||||
using Microsoft.VisualStudio.Threading;
|
||||
using Task = System.Threading.Tasks.Task;
|
||||
|
||||
namespace Microsoft.VisualStudio.SecretManager
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides an thread-safe access the secrets.json file based on the UserSecretsId property in a configured project.
|
||||
/// </summary>
|
||||
internal class ProjectLocalSecretsManager : Shell.IVsProjectSecrets, Shell.SVsProjectLocalSecrets
|
||||
{
|
||||
private const string UserSecretsPropertyName = "UserSecretsId";
|
||||
|
||||
private readonly AsyncSemaphore _semaphore;
|
||||
private readonly IProjectPropertiesProvider _propertiesProvider;
|
||||
private readonly Lazy<IServiceProvider> _services;
|
||||
|
||||
public ProjectLocalSecretsManager(IProjectPropertiesProvider propertiesProvider, Lazy<IServiceProvider> serviceProvider)
|
||||
{
|
||||
_propertiesProvider = propertiesProvider ?? throw new ArgumentNullException(nameof(propertiesProvider));
|
||||
_services = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider));
|
||||
_semaphore = new AsyncSemaphore(1);
|
||||
}
|
||||
|
||||
public string SanitizeName(string name) => name;
|
||||
|
||||
public IReadOnlyCollection<char> GetInvalidCharactersFrom(string name) => Array.Empty<char>();
|
||||
|
||||
public async Task AddSecretAsync(string name, string value, CancellationToken cancellationToken = default)
|
||||
{
|
||||
EnsureKeyNameIsValid(name);
|
||||
await TaskScheduler.Default;
|
||||
|
||||
using (await _semaphore.EnterAsync(cancellationToken))
|
||||
using (var store = await GetOrCreateStoreAsync(cancellationToken))
|
||||
{
|
||||
if (store.ContainsKey(name))
|
||||
{
|
||||
throw new ArgumentException(Resources.Error_SecretAlreadyExists, nameof(name));
|
||||
}
|
||||
|
||||
store.Set(name, value);
|
||||
await store.SaveAsync(cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task SetSecretAsync(string name, string value, CancellationToken cancellationToken = default)
|
||||
{
|
||||
EnsureKeyNameIsValid(name);
|
||||
await TaskScheduler.Default;
|
||||
|
||||
using (await _semaphore.EnterAsync(cancellationToken))
|
||||
using (var store = await GetOrCreateStoreAsync(cancellationToken))
|
||||
{
|
||||
store.Set(name, value);
|
||||
await store.SaveAsync(cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<string> GetSecretAsync(string name, CancellationToken cancellationToken = default)
|
||||
{
|
||||
EnsureKeyNameIsValid(name);
|
||||
await TaskScheduler.Default;
|
||||
|
||||
using (await _semaphore.EnterAsync(cancellationToken))
|
||||
using (var store = await GetOrCreateStoreAsync(cancellationToken))
|
||||
{
|
||||
return store.Get(name);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<IReadOnlyCollection<string>> GetSecretNamesAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
await TaskScheduler.Default;
|
||||
|
||||
using (await _semaphore.EnterAsync(cancellationToken))
|
||||
using (var store = await GetOrCreateStoreAsync(cancellationToken))
|
||||
{
|
||||
return store.ReadOnlyKeys;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public async Task<IReadOnlyDictionary<string, string>> GetSecretsAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
await TaskScheduler.Default;
|
||||
|
||||
using (await _semaphore.EnterAsync(cancellationToken))
|
||||
using (var store = await GetOrCreateStoreAsync(cancellationToken))
|
||||
{
|
||||
return store.Values;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> RemoveSecretAsync(string name, CancellationToken cancellationToken = default)
|
||||
{
|
||||
EnsureKeyNameIsValid(name);
|
||||
await TaskScheduler.Default;
|
||||
|
||||
using (await _semaphore.EnterAsync(cancellationToken))
|
||||
using (var store = await GetOrCreateStoreAsync(cancellationToken))
|
||||
{
|
||||
if (store.Remove(name))
|
||||
{
|
||||
await store.SaveAsync(cancellationToken);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void EnsureKeyNameIsValid(string name)
|
||||
{
|
||||
if (name == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(name));
|
||||
}
|
||||
|
||||
if (name.Length == 0)
|
||||
{
|
||||
throw new ArgumentException(nameof(name));
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<SecretStore> GetOrCreateStoreAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var userSecretsId = await _propertiesProvider.GetCommonProperties().GetEvaluatedPropertyValueAsync(UserSecretsPropertyName);
|
||||
|
||||
if (string.IsNullOrEmpty(userSecretsId))
|
||||
{
|
||||
userSecretsId = Guid.NewGuid().ToString();
|
||||
await _propertiesProvider.GetCommonProperties().SetPropertyValueAsync(UserSecretsPropertyName, userSecretsId);
|
||||
}
|
||||
|
||||
var store = new SecretStore(userSecretsId);
|
||||
await store.LoadAsync(cancellationToken);
|
||||
return store;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Reflection;
|
||||
using Microsoft.VisualStudio.Shell;
|
||||
|
||||
// required for VS to generate the pkgdef
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: ProvideCodeBase(CodeBase = @"$PackageFolder$\Microsoft.VisualStudio.SecretManager.dll")]
|
||||
[assembly: ProvideBindingRedirection(
|
||||
AssemblyName = "Microsoft.VisualStudio.SecretManager",
|
||||
GenerateCodeBase = true,
|
||||
PublicKeyToken = "adb9793829ddae60",
|
||||
OldVersionLowerBound = "0.0.0.0",
|
||||
OldVersionUpperBound = "1.0.0.0",
|
||||
NewVersion = "1.0.0.0")]
|
||||
|
|
@ -0,0 +1,140 @@
|
|||
// <auto-generated />
|
||||
namespace Microsoft.VisualStudio.SecretManager
|
||||
{
|
||||
using System.Globalization;
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
|
||||
internal static class Resources
|
||||
{
|
||||
private static readonly ResourceManager _resourceManager
|
||||
= new ResourceManager("Microsoft.VisualStudio.SecretManager.Resources", typeof(Resources).GetTypeInfo().Assembly);
|
||||
|
||||
/// <summary>
|
||||
/// A secret with this name already exists.
|
||||
/// </summary>
|
||||
internal static string Error_SecretAlreadyExists
|
||||
{
|
||||
get => GetString("Error_SecretAlreadyExists");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Value cannot be null or an empty string.
|
||||
/// </summary>
|
||||
internal static string Common_StringNullOrEmpty
|
||||
{
|
||||
get => GetString("Common_StringNullOrEmpty");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Value cannot be null or an empty string.
|
||||
/// </summary>
|
||||
internal static string FormatCommon_StringNullOrEmpty()
|
||||
=> GetString("Common_StringNullOrEmpty");
|
||||
|
||||
/// <summary>
|
||||
/// Invalid character '{0}' found in the user secrets ID at index '{1}'.
|
||||
/// </summary>
|
||||
internal static string Error_Invalid_Character_In_UserSecrets_Id
|
||||
{
|
||||
get => GetString("Error_Invalid_Character_In_UserSecrets_Id");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invalid character '{0}' found in the user secrets ID at index '{1}'.
|
||||
/// </summary>
|
||||
internal static string FormatError_Invalid_Character_In_UserSecrets_Id(object p0, object p1)
|
||||
=> string.Format(CultureInfo.CurrentCulture, GetString("Error_Invalid_Character_In_UserSecrets_Id"), p0, p1);
|
||||
|
||||
/// <summary>
|
||||
/// Could not find 'UserSecretsIdAttribute' on assembly '{0}'.
|
||||
/// Check that the project for '{0}' has set the 'UserSecretsId' build property.
|
||||
/// If the 'UserSecretsId' property is already set then add a reference to the Microsoft.Extensions.Configuration.UserSecrets package.
|
||||
/// </summary>
|
||||
internal static string Error_Missing_UserSecretsIdAttribute
|
||||
{
|
||||
get => GetString("Error_Missing_UserSecretsIdAttribute");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Could not find 'UserSecretsIdAttribute' on assembly '{0}'.
|
||||
/// Check that the project for '{0}' has set the 'UserSecretsId' build property.
|
||||
/// If the 'UserSecretsId' property is already set then add a reference to the Microsoft.Extensions.Configuration.UserSecrets package.
|
||||
/// </summary>
|
||||
internal static string FormatError_Missing_UserSecretsIdAttribute(object p0)
|
||||
=> string.Format(CultureInfo.CurrentCulture, GetString("Error_Missing_UserSecretsIdAttribute"), p0);
|
||||
|
||||
/// <summary>
|
||||
/// File path must be a non-empty string.
|
||||
/// </summary>
|
||||
internal static string Error_InvalidFilePath
|
||||
{
|
||||
get => GetString("Error_InvalidFilePath");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// File path must be a non-empty string.
|
||||
/// </summary>
|
||||
internal static string FormatError_InvalidFilePath()
|
||||
=> GetString("Error_InvalidFilePath");
|
||||
|
||||
/// <summary>
|
||||
/// Could not parse the JSON file. Error on line number '{0}': '{1}'.
|
||||
/// </summary>
|
||||
internal static string Error_JSONParseError
|
||||
{
|
||||
get => GetString("Error_JSONParseError");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Could not parse the JSON file. Error on line number '{0}': '{1}'.
|
||||
/// </summary>
|
||||
internal static string FormatError_JSONParseError(object p0, object p1)
|
||||
=> string.Format(CultureInfo.CurrentCulture, GetString("Error_JSONParseError"), p0, p1);
|
||||
|
||||
/// <summary>
|
||||
/// A duplicate key '{0}' was found.
|
||||
/// </summary>
|
||||
internal static string Error_KeyIsDuplicated
|
||||
{
|
||||
get => GetString("Error_KeyIsDuplicated");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A duplicate key '{0}' was found.
|
||||
/// </summary>
|
||||
internal static string FormatError_KeyIsDuplicated(object p0)
|
||||
=> string.Format(CultureInfo.CurrentCulture, GetString("Error_KeyIsDuplicated"), p0);
|
||||
|
||||
/// <summary>
|
||||
/// Unsupported JSON token '{0}' was found. Path '{1}', line {2} position {3}.
|
||||
/// </summary>
|
||||
internal static string Error_UnsupportedJSONToken
|
||||
{
|
||||
get => GetString("Error_UnsupportedJSONToken");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unsupported JSON token '{0}' was found. Path '{1}', line {2} position {3}.
|
||||
/// </summary>
|
||||
internal static string FormatError_UnsupportedJSONToken(object p0, object p1, object p2, object p3)
|
||||
=> string.Format(CultureInfo.CurrentCulture, GetString("Error_UnsupportedJSONToken"), p0, p1, p2, p3);
|
||||
|
||||
private static string GetString(string name, params string[] formatterNames)
|
||||
{
|
||||
var value = _resourceManager.GetString(name);
|
||||
|
||||
System.Diagnostics.Debug.Assert(value != null);
|
||||
|
||||
if (formatterNames != null)
|
||||
{
|
||||
for (var i = 0; i < formatterNames.Length; i++)
|
||||
{
|
||||
value = value.Replace("{" + formatterNames[i] + "}", "{" + i + "}");
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,146 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="Error_InvalidFilePath" xml:space="preserve">
|
||||
<value>File path must be a non-empty string.</value>
|
||||
</data>
|
||||
<data name="Error_JSONParseError" xml:space="preserve">
|
||||
<value>Could not parse the JSON file. Error on line number '{0}': '{1}'.</value>
|
||||
</data>
|
||||
<data name="Error_KeyIsDuplicated" xml:space="preserve">
|
||||
<value>A duplicate key '{0}' was found.</value>
|
||||
</data>
|
||||
<data name="Error_UnsupportedJSONToken" xml:space="preserve">
|
||||
<value>Unsupported JSON token '{0}' was found. Path '{1}', line {2} position {3}.</value>
|
||||
</data>
|
||||
<data name="Common_StringNullOrEmpty" xml:space="preserve">
|
||||
<value>Value cannot be null or an empty string.</value>
|
||||
</data>
|
||||
<data name="Error_Invalid_Character_In_UserSecrets_Id" xml:space="preserve">
|
||||
<value>Invalid character '{0}' found in the user secrets ID at index '{1}'.</value>
|
||||
</data>
|
||||
<data name="Error_Missing_UserSecretsIdAttribute" xml:space="preserve">
|
||||
<value>Could not find 'UserSecretsIdAttribute' on assembly '{0}'.
|
||||
Check that the project for '{0}' has set the 'UserSecretsId' build property.
|
||||
If the 'UserSecretsId' property is already set then add a reference to the Microsoft.Extensions.Configuration.UserSecrets package.</value>
|
||||
</data>
|
||||
<data name="Error_SecretAlreadyExists" xml:space="preserve">
|
||||
<value>A secret with this name already exists.</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.ComponentModel.Composition;
|
||||
using Microsoft.VisualStudio.ProjectSystem;
|
||||
using Microsoft.VisualStudio.Shell;
|
||||
|
||||
namespace Microsoft.VisualStudio.SecretManager
|
||||
{
|
||||
internal class SecretManagerFactory
|
||||
{
|
||||
// This is capability is set in Microsoft.Extensions.Configuration.UserSecrets
|
||||
private const string CapabilityName = "LocalUserSecrets";
|
||||
|
||||
private readonly Lazy<ProjectLocalSecretsManager> _secretManager;
|
||||
private readonly UnconfiguredProject _project;
|
||||
|
||||
[ImportingConstructor]
|
||||
public SecretManagerFactory(UnconfiguredProject project, SVsServiceProvider vsServiceProvider)
|
||||
{
|
||||
_project = project;
|
||||
|
||||
var serviceProvider = new Lazy<IServiceProvider>(() => vsServiceProvider);
|
||||
|
||||
_secretManager = new Lazy<ProjectLocalSecretsManager>(() =>
|
||||
{
|
||||
var propertiesProvider = _project.Services.ActiveConfiguredProjectProvider.ActiveConfiguredProject.Services.ProjectPropertiesProvider;
|
||||
return new ProjectLocalSecretsManager(propertiesProvider, serviceProvider);
|
||||
});
|
||||
}
|
||||
|
||||
[ExportVsProfferedProjectService(typeof(SVsProjectLocalSecrets))]
|
||||
[AppliesTo(CapabilityName)]
|
||||
public SVsProjectLocalSecrets ProjectLocalSecretsManager => _secretManager.Value;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,169 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Configuration.Json;
|
||||
using Microsoft.Extensions.Configuration.UserSecrets;
|
||||
using Microsoft.VisualStudio.Threading;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Task = System.Threading.Tasks.Task;
|
||||
|
||||
namespace Microsoft.VisualStudio.SecretManager
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides read and write access to the secrets.json file for local user secrets.
|
||||
/// This is not thread-safe.
|
||||
/// This object is meant to have a short lifetime.
|
||||
/// When calling <see cref="SaveAsync(CancellationToken)"/>, this will overwrite the secrets.json file. It does not check for concurrency issues if another process has edited this file.
|
||||
/// </summary>
|
||||
internal class SecretStore : IDisposable
|
||||
{
|
||||
private Dictionary<string, string> _secrets;
|
||||
private string _fileDir;
|
||||
private string _filePath;
|
||||
private bool _isDirty;
|
||||
private volatile bool _disposed;
|
||||
|
||||
public SecretStore(string userSecretsId)
|
||||
{
|
||||
_filePath = PathHelper.GetSecretsPathFromSecretsId(userSecretsId);
|
||||
_fileDir = Path.GetDirectoryName(_filePath);
|
||||
}
|
||||
|
||||
public IReadOnlyCollection<string> ReadOnlyKeys
|
||||
{
|
||||
get
|
||||
{
|
||||
EnsureNotDisposed();
|
||||
return _secrets.Keys;
|
||||
}
|
||||
}
|
||||
|
||||
public IReadOnlyDictionary<string, string> Values
|
||||
{
|
||||
get
|
||||
{
|
||||
EnsureNotDisposed();
|
||||
|
||||
return _secrets;
|
||||
}
|
||||
}
|
||||
|
||||
public bool ContainsKey(string key)
|
||||
{
|
||||
EnsureNotDisposed();
|
||||
|
||||
return _secrets.ContainsKey(key);
|
||||
}
|
||||
|
||||
public string Get(string name)
|
||||
{
|
||||
EnsureNotDisposed();
|
||||
|
||||
return _secrets[name];
|
||||
}
|
||||
|
||||
public void Set(string key, string value)
|
||||
{
|
||||
EnsureNotDisposed();
|
||||
|
||||
_isDirty = true;
|
||||
_secrets[key] = value;
|
||||
}
|
||||
|
||||
public bool Remove(string key)
|
||||
{
|
||||
EnsureNotDisposed();
|
||||
_isDirty = true;
|
||||
return _secrets.Remove(key);
|
||||
}
|
||||
|
||||
public async Task LoadAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
await TaskScheduler.Default;
|
||||
|
||||
EnsureNotDisposed();
|
||||
|
||||
string text = null;
|
||||
|
||||
if (File.Exists(_filePath))
|
||||
{
|
||||
text = File.ReadAllText(_filePath);
|
||||
}
|
||||
|
||||
_secrets = DeserializeJson(text);
|
||||
}
|
||||
|
||||
public async Task SaveAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
await TaskScheduler.Default;
|
||||
|
||||
EnsureNotDisposed();
|
||||
|
||||
if (!_isDirty)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Directory.CreateDirectory(_fileDir);
|
||||
File.WriteAllText(_filePath, Stringify(_secrets), Encoding.UTF8);
|
||||
|
||||
_isDirty = false;
|
||||
}
|
||||
|
||||
private void EnsureNotDisposed()
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
throw new ObjectDisposedException(nameof(SecretStore));
|
||||
}
|
||||
}
|
||||
|
||||
private static string Stringify(Dictionary<string, string> secrets)
|
||||
{
|
||||
var contents = new JObject();
|
||||
if (secrets != null)
|
||||
{
|
||||
foreach (var secret in secrets)
|
||||
{
|
||||
contents[secret.Key] = secret.Value;
|
||||
}
|
||||
}
|
||||
|
||||
return contents.ToString();
|
||||
}
|
||||
|
||||
private static Dictionary<string, string> DeserializeJson(string text)
|
||||
{
|
||||
if (string.IsNullOrEmpty(text))
|
||||
{
|
||||
return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
using (var stream = new MemoryStream())
|
||||
{
|
||||
var bytes = Encoding.UTF8.GetBytes(text);
|
||||
stream.Write(bytes, 0, bytes.Length);
|
||||
stream.Position = 0;
|
||||
|
||||
// might throw FormatException if JSON is malformed.
|
||||
var data = JsonConfigurationFileParser.Parse(stream);
|
||||
|
||||
return new Dictionary<string, string>(data, StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_disposed) return;
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.Extensions.Configuration
|
||||
{
|
||||
/// <summary>
|
||||
/// Utility methods and constants for manipulating Configuration paths
|
||||
/// </summary>
|
||||
internal static class ConfigurationPath
|
||||
{
|
||||
/// <summary>
|
||||
/// The delimiter ":" used to separate individual keys in a path.
|
||||
/// </summary>
|
||||
public static readonly string KeyDelimiter = ":";
|
||||
|
||||
/// <summary>
|
||||
/// Combines path segments into one path.
|
||||
/// </summary>
|
||||
/// <param name="pathSegments">The path segments to combine.</param>
|
||||
/// <returns>The combined path.</returns>
|
||||
public static string Combine(params string[] pathSegments)
|
||||
{
|
||||
if (pathSegments == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(pathSegments));
|
||||
}
|
||||
return string.Join(KeyDelimiter, pathSegments);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Combines path segments into one path.
|
||||
/// </summary>
|
||||
/// <param name="pathSegments">The path segments to combine.</param>
|
||||
/// <returns>The combined path.</returns>
|
||||
public static string Combine(IEnumerable<string> pathSegments)
|
||||
{
|
||||
if (pathSegments == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(pathSegments));
|
||||
}
|
||||
return string.Join(KeyDelimiter, pathSegments);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extracts the last path segment from the path.
|
||||
/// </summary>
|
||||
/// <param name="path">The path.</param>
|
||||
/// <returns>The last path segment of the path.</returns>
|
||||
public static string GetSectionKey(string path)
|
||||
{
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
var lastDelimiterIndex = path.LastIndexOf(KeyDelimiter, StringComparison.OrdinalIgnoreCase);
|
||||
return lastDelimiterIndex == -1 ? path : path.Substring(lastDelimiterIndex + 1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extracts the path corresponding to the parent node for a given path.
|
||||
/// </summary>
|
||||
/// <param name="path">The path.</param>
|
||||
/// <returns>The original path minus the last individual segment found in it. Null if the original path corresponds to a top level node.</returns>
|
||||
public static string GetParentPath(string path)
|
||||
{
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var lastDelimiterIndex = path.LastIndexOf(KeyDelimiter, StringComparison.OrdinalIgnoreCase);
|
||||
return lastDelimiterIndex == -1 ? null : path.Substring(0, lastDelimiterIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Microsoft.VisualStudio.SecretManager;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Microsoft.Extensions.Configuration.Json
|
||||
{
|
||||
internal class JsonConfigurationFileParser
|
||||
{
|
||||
private JsonConfigurationFileParser() { }
|
||||
|
||||
private readonly IDictionary<string, string> _data = new SortedDictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
private readonly Stack<string> _context = new Stack<string>();
|
||||
private string _currentPath;
|
||||
|
||||
private JsonTextReader _reader;
|
||||
|
||||
public static IDictionary<string, string> Parse(Stream input)
|
||||
=> new JsonConfigurationFileParser().ParseStream(input);
|
||||
|
||||
private IDictionary<string, string> ParseStream(Stream input)
|
||||
{
|
||||
_data.Clear();
|
||||
_reader = new JsonTextReader(new StreamReader(input));
|
||||
_reader.DateParseHandling = DateParseHandling.None;
|
||||
|
||||
var jsonConfig = JObject.Load(_reader);
|
||||
|
||||
VisitJObject(jsonConfig);
|
||||
|
||||
return _data;
|
||||
}
|
||||
|
||||
private void VisitJObject(JObject jObject)
|
||||
{
|
||||
foreach (var property in jObject.Properties())
|
||||
{
|
||||
EnterContext(property.Name);
|
||||
VisitProperty(property);
|
||||
ExitContext();
|
||||
}
|
||||
}
|
||||
|
||||
private void VisitProperty(JProperty property)
|
||||
{
|
||||
VisitToken(property.Value);
|
||||
}
|
||||
|
||||
private void VisitToken(JToken token)
|
||||
{
|
||||
switch (token.Type)
|
||||
{
|
||||
case JTokenType.Object:
|
||||
VisitJObject(token.Value<JObject>());
|
||||
break;
|
||||
|
||||
case JTokenType.Array:
|
||||
VisitArray(token.Value<JArray>());
|
||||
break;
|
||||
|
||||
case JTokenType.Integer:
|
||||
case JTokenType.Float:
|
||||
case JTokenType.String:
|
||||
case JTokenType.Boolean:
|
||||
case JTokenType.Bytes:
|
||||
case JTokenType.Raw:
|
||||
case JTokenType.Null:
|
||||
VisitPrimitive(token.Value<JValue>());
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new FormatException(Resources.FormatError_UnsupportedJSONToken(
|
||||
_reader.TokenType,
|
||||
_reader.Path,
|
||||
_reader.LineNumber,
|
||||
_reader.LinePosition));
|
||||
}
|
||||
}
|
||||
|
||||
private void VisitArray(JArray array)
|
||||
{
|
||||
for (int index = 0; index < array.Count; index++)
|
||||
{
|
||||
EnterContext(index.ToString());
|
||||
VisitToken(array[index]);
|
||||
ExitContext();
|
||||
}
|
||||
}
|
||||
|
||||
private void VisitPrimitive(JValue data)
|
||||
{
|
||||
var key = _currentPath;
|
||||
|
||||
if (_data.ContainsKey(key))
|
||||
{
|
||||
throw new FormatException(Resources.FormatError_KeyIsDuplicated(key));
|
||||
}
|
||||
_data[key] = data.ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
private void EnterContext(string context)
|
||||
{
|
||||
_context.Push(context);
|
||||
_currentPath = ConfigurationPath.Combine(_context.Reverse());
|
||||
}
|
||||
|
||||
private void ExitContext()
|
||||
{
|
||||
_context.Pop();
|
||||
_currentPath = ConfigurationPath.Combine(_context.Reverse());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using Microsoft.VisualStudio.SecretManager;
|
||||
|
||||
namespace Microsoft.Extensions.Configuration.UserSecrets
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides paths for user secrets configuration files.
|
||||
/// </summary>
|
||||
internal class PathHelper
|
||||
{
|
||||
internal const string SecretsFileName = "secrets.json";
|
||||
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// Returns the path to the JSON file that stores user secrets.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// This uses the current user profile to locate the secrets file on disk in a location outside of source control.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <param name="userSecretsId">The user secret ID.</param>
|
||||
/// <returns>The full path to the secret file.</returns>
|
||||
public static string GetSecretsPathFromSecretsId(string userSecretsId)
|
||||
{
|
||||
if (string.IsNullOrEmpty(userSecretsId))
|
||||
{
|
||||
throw new ArgumentException(Resources.Common_StringNullOrEmpty, nameof(userSecretsId));
|
||||
}
|
||||
|
||||
var badCharIndex = userSecretsId.IndexOfAny(Path.GetInvalidFileNameChars());
|
||||
if (badCharIndex != -1)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
string.Format(
|
||||
Resources.Error_Invalid_Character_In_UserSecrets_Id,
|
||||
userSecretsId[badCharIndex],
|
||||
badCharIndex));
|
||||
}
|
||||
|
||||
var root = Environment.GetEnvironmentVariable("APPDATA") ?? // On Windows it goes to %APPDATA%\Microsoft\UserSecrets\
|
||||
Environment.GetEnvironmentVariable("HOME"); // On Mac/Linux it goes to ~/.microsoft/usersecrets/
|
||||
|
||||
if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("APPDATA")))
|
||||
{
|
||||
return Path.Combine(root, "Microsoft", "UserSecrets", userSecretsId, SecretsFileName);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Path.Combine(root, ".microsoft", "usersecrets", userSecretsId, SecretsFileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011" xmlns:d="http://schemas.microsoft.com/developer/vsx-schema-design/2011">
|
||||
<Metadata>
|
||||
<Identity Id="Microsoft.VisualStudio.SecretManager.11eea7f6-8d34-4759-b618-b40f454266d4" Version="|%CurrentProject%;GetBuildVersion|" Language="en-US" Publisher="Microsoft" />
|
||||
<DisplayName>Microsoft.VisualStudio.SecretManager</DisplayName>
|
||||
<Description xml:space="preserve">Enables IVsProjectSecrets for ASP.NET Core projects that use Microsoft.Extensions.Configuration.UserSecrets.</Description>
|
||||
</Metadata>
|
||||
<Installation>
|
||||
<InstallationTarget Id="Microsoft.VisualStudio.Community" Version="[15.0.26228.04,)" />
|
||||
</Installation>
|
||||
<Dependencies>
|
||||
<Dependency Id="Microsoft.Framework.NDP" DisplayName="Microsoft .NET Framework" d:Source="Manual" Version="[4.6,)" />
|
||||
<Dependency Id="Microsoft.VisualStudio.MPF.15.0" DisplayName="Visual Studio MPF 15.0" d:Source="Installed" Version="[15.0]" />
|
||||
</Dependencies>
|
||||
<Prerequisites>
|
||||
<Prerequisite Id="Microsoft.VisualStudio.Component.CoreEditor" Version="[15.0)" DisplayName="Visual Studio core editor" />
|
||||
</Prerequisites>
|
||||
<Assets>
|
||||
<Asset Type="Microsoft.VisualStudio.MefComponent" d:Source="Project" d:ProjectName="%CurrentProject%" Path="|%CurrentProject%|" />
|
||||
</Assets>
|
||||
</PackageManifest>
|
||||
|
|
@ -1,9 +1,12 @@
|
|||
<Project>
|
||||
<PropertyGroup>
|
||||
<VersionPrefix>2.1.0</VersionPrefix>
|
||||
<VsixVersion>15.6</VsixVersion>
|
||||
<VersionSuffix>preview1</VersionSuffix>
|
||||
<PackageVersion Condition="'$(IsFinalBuild)' == 'true' AND '$(VersionSuffix)' == 'rtm' ">$(VersionPrefix)</PackageVersion>
|
||||
<PackageVersion Condition="'$(IsFinalBuild)' == 'true' AND '$(VersionSuffix)' != 'rtm' ">$(VersionPrefix)-$(VersionSuffix)-final</PackageVersion>
|
||||
<VsixVersion Condition="'$(BuildNumber)' != ''">$(VsixVersion).$(BuildNumber)</VsixVersion>
|
||||
<VsixVersion Condition="'$(BuildNumber)' == ''">$(VsixVersion).999999</VsixVersion>
|
||||
<BuildNumber Condition="'$(BuildNumber)' == ''">t000</BuildNumber>
|
||||
<VersionSuffix Condition="'$(VersionSuffix)' != '' And '$(BuildNumber)' != ''">$(VersionSuffix)-$(BuildNumber)</VersionSuffix>
|
||||
</PropertyGroup>
|
||||
|
|
|
|||
Loading…
Reference in New Issue