logo

.env – an engima in .net

While working on some code last night, I came to a point where I needed to retrieve a Postgres connection string from a settings file. I decided that I wanted to do it via a .env file, a common practice for the Node projects that I work on. Thanks to a bit of googling, I took on this dependency and added the following code to a Settings.cs file:

public static class Settings
{
    static Settings()
    {
        DotNetEnv.Env.Load();
    }

    public static string ConnectionString => DotNetEnv.Env.GetString("POSTGRES_CONNECTION_STRING");
}

If you try and access the ConnectionString property of this class, you’ll get a runtime error similar to:

--- System.IO.FileNotFoundException : Could not find file '\bin\Debug\netcoreapp2.0\.env'.

The dotnet-env library expects to have a .env file in the root of wherever your code is executing. While I do have that .env file in the root of my source, it’s not being copied into my build output.

.env and .env.example

Normally, I would just call out this file directly in my .csproj and include it in the build output. But, that’s not going to work here – the typical pattern for using .env files is that you include a .env.example file in the root of your project, and it is up to the person running your project to copy that to a .env file and add their specific config values. What this means is that there is no guarnatee that the .env file exists at build time, and if your .csproj file is instructing msbuild to copy a .env file when building, you’re build will fail when that file is missing.

That’s a mouth full, and it felt as much when I was half-awake trying to solve this problem. But, I think I figured it out.

You can use a wildcard to include (or exclude) files in your build output. The sage advice online seems to be that using a Content tag in your .csproj file is the way to go, but I couldn’t get that to work. My assumption is that becuase the .env file is not actually a part of a broader solution, the Content tag doesn’t work. But, adding this to my .csproj file did work:

<ItemGroup>
  <None Include="*.env" CopyToOutputDirectory="Always" />
</ItemGroup>

This ensures that if there is a .env file present in the root of my source, that file is copied over to the build output. If you know of a better way to do this, I’d love to hear about it.

I hope this is helpful to you, especially if you are solving this problem in the wee hours of the morning! :)