This article provides code that works for dotnet version 2.1.4. It important to note that as the API for accomplishing this seems to change with every release. I found that out the hard way.
While trying to show students how to get an environment variable, or configuration setting for their third-party API keys into JavaScript, I figured I'd quickly find out how to accomplish that in ASP.NET Core. Well, 2.5 hours later I was having a discussion with them about how this is what the life of a software developer looks like.
- Determine problem to solve
- Discover that the solution isn't obvious
- Google search
- Read 5 articles
- Realize they are all grotesquely outdated
- Find 1 or 2 promising ones
- Try the solutions
- Neither works
- Repeat 3-7 until 8 doesn't happen any more
After going through that process for the 875,201st time in my career, I'm letting others know my solution.
Create Settings
Open your appsettings.json
file and add a configuration section. In the JSON below, I've added an ApplicationConfiguration object to the settings.
{
"ConnectionStrings": {
"DefaultConnection": "Data Source=MovieHistory.db"
},
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
},
"ApplicationConfiguration": {
"MovieAPIKey": "9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f"
}
}
Create Service Interface
Next, you need to create a service which can be injected into the Razor template. First, create an interface
. Here's my Services/IApplicationConfiguration.cs
file.
namespace MovieHistory.Services
{
public interface IApplicationConfiguration
{
/*
Note that each property here needs to exactly match the
name of each property in my appsettings.json config object
*/
string MovieAPIKey { get; set; }
}
}
Next, you'll need an implementation of the service. Below is my Services/ApplicationConfiguration.cs
file.
namespace MovieHistory.Services
{
public class ApplicationConfiguration: IApplicationConfiguration
{
/*
Note that each property here needs to exactly match the
name of each property in my appsettings.json config object
*/
public string MovieAPIKey { get; set; }
}
}
These two files create the base for a service. Now it's time to register the service in your application.
Register the Service
In Startup.cs
, I use service.AddSingleton
to register my service in the ConfigureServices
method.
public void ConfigureServices(IServiceCollection services)
{
...
/**
Create a service for DI that will return the ApplicationConfiguration
section of appsettings. This is just a factory function.
*/
services.AddSingleton<IApplicationConfiguration, ApplicationConfiguration>(
e => Configuration.GetSection("ApplicationConfiguration")
.Get<ApplicationConfiguration>());
services.AddMvc();
}
Inject the Service into Razor Template
Now I can use it in Views/Shared/_Layout.cshtml
by using the @inject
directive, and then accessing the MovieAPIKey
property in the script tag.
@inject MovieHistory.Services.IApplicationConfiguration AppSettings;
<!DOCTYPE html>
<html>
<head>...</head>
<body>
...
<environment include="Development">
<script type="text/javascript">
const moviedb = Object.create(null, {
"key": {
get: () => '@AppSettings.MovieAPIKey'
}
})
Object.freeze(moviedb)
</script>
<script src="~/lib/jquery/dist/jquery.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.js"></script>
<script src="~/js/site.js" asp-append-version="true"></script>
</environment>
</body>
</html>
Inject into Controller
I wanted the configuration setting to be used in the _Layout.cshtml
so that it was available in every view, but if you have configuration that's only needed in a particular controller, or a particular method, you can use dependency injection to get the singleton that was configured in Startup.cs
(see above) injected into a controller's constructor method.
public class HomeController : Controller
{
private readonly IApplicationConfiguration _appSettings;
public HomeController(IApplicationConfiguration appSettings)
{
_appSettings = appSettings;
}
public IActionResult Index()
{
ViewData["apiKey"] = _appSettings.MovieAPIKey;
return View();
}
}