Microsoft.Extensions.Configuration.UserSecrets.targets injects source file as last in project to compile
vdehaven opened this issue · comments
Title
Microsoft.Extensions.Configuration.UserSecrets.targets injects source file as last in project to compile
Functional impact
This ordering precludes the package's use in F# dotnet console applications.
Minimal repro steps
- Create an F# console app.
dotnet new console --language F#
- Add Microsoft.Extensions.SecretManager.Tools package.
dotnet add package Microsoft.Extensions.SecretManager.Tools
- Add a user secrets ID and the tools reference for secret creation.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.0</TargetFramework>
<UserSecretsId>aGUIDmaybe</UserSecretsId>
</PropertyGroup>
<ItemGroup>
<Compile Include="Program.fs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.SecretManager.Tools" Version="2.0.2" />
<DotNetCliToolReference Include="Microsoft.Extensions.SecretManager.Tools" Version="2.0.2" />
</ItemGroup>
</Project>
- Add a secret.
dotnet user-secrets set MySecret ThisIsMySecret
- Replace Program.fs with the following:
module Program
open Microsoft.Extensions.Configuration
open System
[<EntryPoint>]
let main _ =
let builder = ((new ConfigurationBuilder())
.SetBasePath Environment.CurrentDirectory)
.AddUserSecrets()
let config = builder.Build()
printfn "Here's your secret setting: %s" config.["MySecret"]
0
- Restore and build
dotnet restore; dotnet build --verbosity detailed
Expected result
The generated UserSecretsAssemblyInfo.fs should be compiled prior to the last file, e.g., the file with the [<EntryPoint>]
attribute.
Actual result
UserSecretsAssemblyInfo.fs is compiled last, as seen in the verbose build output.
C:\Users\username\AppData\Local\Temp.NETCoreApp,Version=v2.0.AssemblyAttributes.fs
Program.fs
obj\Debug\netcoreapp2.0\UserSecretsAssemblyInfo.fs
This results in:
error FS0433: A function labeled with the 'EntryPointAttribute' attribute must be the last declaration in the last file in the compilation sequence.
Further technical details
- Windows 10.0.16299
- .NET SDK 2.1.105
- Microsoft.Extensions.SecretManager.Tools 2.0.2
Attempting to circumvent the compile order by adding the generated assembly info file via
<Compile Include="**/UserSecretsAssemblyInfo.fs" />
is foiled by the UserSecrets.targets file:
<ItemGroup>
<!--Ensure generated file is not already in compile sources-->
<Compile Remove="$(GeneratedUserSecretsAttributeFile)" />
</ItemGroup>
A work-around
Remove the <UserSecretsId>
element from the .fsproj. Instead, load the user secrets ID from an appsettings file, such as:
{
"userSecretsId": "aGUIDmaybe"
}
using:
[<EntryPoint>]
let main _ =
printfn "Loading configuration..."
let builder = ((new ConfigurationBuilder())
.SetBasePath Environment.CurrentDirectory)
.AddJsonFile "Properties/appsettings.json"
let intermediate = builder.Build() // Intermediate build to get the user secrets.
let builder = builder.AddUserSecrets(intermediate.["userSecretsId"])
let config = builder.Build()
printfn "Here's your secret setting: %s" config.["MySecret"]
0
Ran into this issue with latest SDK and packages, so still not solved.
@vdehaven Thanks for the workaround!
Resolved with #872.