44

I'm writing a basic app to learn ASP.NET 5. One area I find very confusing is configuration. Prior to ASP.NET 5, I could do the following:

var settingValue = ConfigurationManager.AppSettings["SomeKey"];

I would have lines of code like that sprinkled throughout my code. Now, in the vNext world, I have a config.json file that looks like this:

config.json

{
  "AppSettings": {
    "SomeKey":"SomeValue"
  }
}

Then in Startup.cs, I have the following: Startup.cs

public IConfiguration Configuration { get; set; }
public Startup(IHostingEnvironment environment) 
{
  Configuration = new Configuration()
      .AddJsonFile("config.json");
}

From there, I'm totally stumped. I have MyClass.cs in /src/Website/Code/Models/MyClass.cs.

MyClass.cs

public class MyClass
{
  public string DoSomething() 
  {
    var result = string.Empty;
    var keyValue = string.Empty; // TODO: What do I do here? How do I get the value of "AppSettings:SomeKey"?
    return result;
  }
}

How do I get the value of "AppSettings:SomeKey"?

mason
  • 31,774
  • 10
  • 77
  • 121
xam developer
  • 1,923
  • 5
  • 27
  • 39

4 Answers4

17

ASP.NET 5 makes heavy use of Dependency Injection, so if you are also using Dependency Injection then this is very simple. If you examine the sample MVC6 project, you can see how this works:

First, there's a class AppSettings defined in Properties, which is a strongly-typed version of the options your class supports. In the sample project, this just contains SiteTitle.

public class AppSettings
{
    public string SiteTitle { get; set; }
}

Then, this class is initialised through dependency injection in ConfigureServices. Configuration here is the one you created in the constructor of the Startup class.

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<AppSettings>(Configuration.GetSubKey("AppSettings"));
    // ...
}

Then, assuming your class is instantiated by the dependency injection container, you can simply ask for an IOptions and you'll get one. For example, in a controller you could have the following:

public class HomeController
{
    private string _title;
    public HomeController(IOptions<AppSettings> settings) 
    {
        _title = settings.Options.SiteTitle;
    }
}
Richard
  • 29,854
  • 11
  • 77
  • 120
  • I'm curious, which sample MVC6 project are you referring to? Do you have a link? – Some User May 22 '15 at 19:01
  • The one you get when you do new MVC project in Visual Studio – Richard May 22 '15 at 19:08
  • 3
    @SerjSagan How did you get this to work. On my system `Configuration` does not have a `GetSubKey` method. – Matthew Verstraete Feb 02 '16 at 22:22
  • 6
    There's a couple of ways. For root level stuff use `Configuration.GetSection("AppSettings")` For nested stuff use `Configuration["Data:DefaultConnection:ConnectionString"]` – Serj Sagan Feb 02 '16 at 22:47
  • 3
    Just to note that, as of today with Asp.Net Core RC1 already out and RC2 *coming*, this *Options Model* is the suggested way to go. The interface changed a little: now it would be `settings.Value.SiteTitle`, plus in `ConfigureServices` one needs `services.AddOptions();` to setup options with DI – superjos Apr 29 '16 at 10:01
15

I use ASP.NET 5 dependency injection, like so.

config.json:

{
    "random":  "Hello World!"
}

startup.cs:

public class Startup
{
    public Startup(IHostingEnvironment env, IApplicationEnvironment appEnv)
    {
        var builder = new ConfigurationBuilder(appEnv.ApplicationBasePath)
            .AddJsonFile("config.json");

        Configuration = builder.Build();
    }

    public IConfiguration Configuration { get; set; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc();
        services.AddSingleton<IConfiguration>(sp => { return Configuration; });
    }

    public void Configure(IApplicationBuilder app)
    {
        app.UseMvc(routes =>
        {
            routes.MapRoute(name: "default", template: "{controller=Home}/{action=Index}/{id?}");
        });

    }

}

Controller:

public class HomeController : Controller
{

    IConfiguration config;

    public HomeController(IConfiguration config)
    {
        this.config = config;
    }

    public IActionResult Index()
    {
        var template = "<marquee>{0}</marquee>";
        var content = string.Format(template, config.Get("random"));
        return Content(content, "text/html");
    }
}
Andy Taw
  • 2,794
  • 1
  • 17
  • 9
  • 1
    In the latest version of ASP.NET Core, `var builder = new ConfigurationBuilder().AddJsonFile("appsettings.json")` – Vahid Amiri Apr 02 '16 at 20:46
  • ... and [changed yet again](https://learn.microsoft.com/en-us/aspnet/core/migration/1x-to-2x/#add-configuration-providers) in Core 2.0. – Marc L. Jan 11 '18 at 22:48
14

I highly recommend using the OptionsModel instead of reading the configuration directly. It allows strong typed model binding to configuration.

Here is an example: GitHub.com/aspnet/Options/test/Microsoft.Extensions.Options.Test/OptionsTest.cs

For your particular case create a model:

class AppSettings {
    public string SomeSetting {get;set;}
}

and then bind it to your configuration:

var config = // The configuration object
var options = ConfigurationBinder.Bind<AppSettings>(config); 
Console.WriteLine(options.SomeSetting);

That way you don't have to worry from where the setting comes from, how it is stored or what is the structure. You simply predefine your options model and magic happens.

orad
  • 15,272
  • 23
  • 77
  • 113
Victor Hurdugaci
  • 28,177
  • 5
  • 87
  • 103
  • With the `OptionsModel` approach, how should one define `AppSettings` for more complex config.json scenarios? For example, what if config.json looked like `{ "AppSettings": { "SiteTitle":"My Site"}, "SearchSettings":{"Service.Key":"12345"}}` – Some User May 22 '15 at 20:12
  • 1
    Create a few classes with properties. Similar to the code [here](https://github.com/aspnet/Options/blob/dev/test/Microsoft.Framework.OptionsModel.Test/OptionsTest.cs#L23) that has `NestedOptions` – Victor Hurdugaci May 22 '15 at 21:36
  • I reveiwed the OptionsModel approach. Yet, its not clear to me the value other than strongly typed values. The larger problem that I think exists with the OptionsModel approach is getting values into a reusable library. For example, what if I wanted to create a re-usable logging library? How would the options get to that library? – Some User May 24 '15 at 15:42
  • It appears to me that this functionality isn't so much the OptionsModel as it is the [ConfigurationBinder](https://github.com/aspnet/Configuration/blob/dev/src/Microsoft.Framework.Configuration.Binder/ConfigurationBinder.cs) at work. I've been trying to figure out the point of Options (`IOption`, `OptionManager`, etc) and haven't really arrived yet. – Ben Collins Jun 20 '15 at 14:44
  • ConfiguratioBinder has been recently moved to Configuration from Options – Victor Hurdugaci Jun 20 '15 at 16:35
  • @VictorHurdugaci Could you tell me the a way I can get these configuration settings from my asp.net 5 web app down to a class library (package) repository. For example my DataLibrary.BaseRepository needs a connection string passed to it from the web app. – Blake Rivell Jan 26 '16 at 14:54
  • @VictorHurdugaci The link in your answer is broken. Can you link to a new example? I am not sure where I should be declaring and filling the `options` variable from your code snippet. – Matthew Verstraete Feb 02 '16 at 21:34
  • @MatthewVerstraete thanks for letting me know. I've fixed the link – Victor Hurdugaci Feb 02 '16 at 22:13
  • 2
    @VictorHurdugaci Thanks for fixing the link, unfortunately for me I still have no idea how to actually get the data from either the `project.json` or `config.json`. – Matthew Verstraete Feb 02 '16 at 22:21
12

Use this:

var value = Configuration.Get("AppSettings:SomeKey");

Based on this blog post. The colon is similar to dot notation and is used for navigation down the hierarchy.

If you need the value in other classes, you should inject it in. ASP.NET has built in dependency injection, but if you just need one instance of MyClass you can new it up instead of setting up a DI container.

public IConfiguration Configuration { get; set; }

public Startup(IHostingEnvironment environment) 
{
    Configuration = new Configuration()
      .AddJsonFile("config.json");
    //generally here you'd set up your DI container. But for now we'll just new it up
    MyClass c = new MyClass(Configuration.Get("AppSettings:SomeKey"));
}

public class MyClass
{
    private readonly string Setting; //if you need to pass multiple objects, use a custom POCO (and interface) instead of a string.

    public MyClass(string setting) //This is called constructor injection
    {
        Setting = setting;
    }

    public string DoSomething() 
    {
        var result = string.Empty;
        //Use setting here
        return result;
    }
}
mason
  • 31,774
  • 10
  • 77
  • 121
  • Where does the `Configuration` property/class come from? I added `using Microsoft.Framework.ConfigurationModel` to top of `MyClass.cs`. However, I cannot use `Configuration.Get` – xam developer May 15 '15 at 19:07
  • It's in [Microsoft.Framework.ConfigurationModel](https://github.com/aspnet/Configuration/blob/dev/src/Microsoft.Framework.ConfigurationModel/Configuration.cs). And you can store your configuration wherever you like in memory instead of reading from the file each time. But I suggest you centralize it so you don't strew it all throughout your code. – mason May 15 '15 at 19:52
  • Sorry but I downvoted your answer because you can use the `OptionsModel` to the model binding. There is no need to read the configuration yourself. (see my answer) – Victor Hurdugaci May 16 '15 at 02:39
  • Man, this is ugly. Better make something like `class MyClass { public MyClass(IConfiguration config...` – metadings May 16 '15 at 11:24
  • 21
    @VictorHurdugaci You are certainly welcome to use downvotes as you see fit. But I think that's an incredibly poor reason to downvote someone's answer. It's a new architecture, I wasn't aware of the option for that. I have watched plenty of demos from your company and none of them have shown a strongly typed model binding option. My answer would work just fine and cleanly shows how to solve the problem. Sure strongly typed model binding is nice, but I would think it rude to go around downvoting people that have alternative working answers, especially if my company were the one suggesting them. – mason May 16 '15 at 12:26
  • @metadings Did you read my answer? I suggested that in my answer. The reason I did not do that was because I didn't want to manipulate the original code out of recognition. You have to learn to walk before you run. – mason May 16 '15 at 12:27
  • 10
    @Victor Seriously bad form to downvote someone else's answer just because you like yours better. Downvotes are for wrong answers or inappropriate ones. If the answer answers the question in a way that works then show it some respect. – drobertson Mar 24 '16 at 00:11