Appsettings.json

.Net Core uses appsettings.json instead of Web.Config with ConfigurationManager. .Net Core allows you to read settings from many sources, but this is going to focus on the standard appsettings file.

Make sure appsettings.json is set to "Copy to Output Directory".

Use appsettings.json for prod settings.
Use appsettings.Development.json to override prod settings with development values.

With Startup

Default Program class will setup configuration

public static IWebHostBuilder CreateWebHostBuilder(string[] args) {
    return WebHost
        .CreateDefaultBuilder(args) //this line sets up configuration
        .UseStartup<Startup>();
}
Use dependency injection to access configuration

using Microsoft.Extensions.Configuration; //from Microsoft.Extensions.Configuration.Abstractions.dll

public ClassConstructor(IConfiguration configRoot)
{
}

Without Startup

Access appsettings without a Startup() method

using Microsoft.Extensions.Configuration;
//also install Microsoft.Extensions.Configuration.Json
//also install Microsoft.Extensions.Configuration.FileExtensions

public static IConfiguration GetConfig()
{
    var builder = new ConfigurationBuilder()
        .SetBasePath(System.AppContext.BaseDirectory)
        .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);

    return builder.Build();
}

Accessing Settings

Sample json and lookup commands

{
    "fieldA": "textA",
    "fieldB": {
        "fieldB1": "textB1"
    }
}

var settings = configRoot; //from Startup example
var settings = ConfigurationHelper.GetConfig(); //from without Startup example
Assert.AreEqual("textA", settings["fieldA"]);
Assert.AreEqual("textB1", settings["fieldB:fieldB1"]);

Options Pattern

You can bind a section of settings to strongly-typed objects.


{
    "Connection": {
        "Database": "db_connection_string",
        "Timeout": 30
    }
}

public class ConnectionOptions
{
    public string Database { get; set; }
    public int Timeout { get; set; }
}

Manual binding

var connectionOptions = new ConnectionOptions();
Configuration.GetSection("Connection").Bind(connectionOptions);

Dependency Injection binding

//in Startup.cs
public void ConfigureServices(IServiceCollection services)
{
    services.Configure<ConnectionOptions>(Configuration.GetSection("Connection"));
    services.AddMvc();
}
//Dependency Injection
using Microsoft.Extensions.Options;
public ClassConstructor(IOptions<ConnectionOptions> options)
{
    ConnectionOptions settings = options.Value;
}

Note that Entity Framework Core DbContext(connectionStringName) will look for appsettings section "ConnectionStrings" with a field named that same as the connectionStringName value.
Or set it explicitly

using Microsoft.EntityFrameworkCore; //with Microsoft.EntityFrameworkCore.dll and Microsoft.EntityFrameworkCore.SqlServer.dll installed

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<MyDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("NamesDatabase")));
} 
With appsettings.json

{
  "ConnectionStrings": {
    "NamesDatabase": "Data Source=(LocalDb)\\MSSQLLocalDB;Initial Catalog=NameDatabase;Integrated Security=True;"
  }
}

Including Settings From Environment Variables

For production, settings like connection strings will be set as an Environment Variable instead of being hard-coded and version controlled.


var builder = new ConfigurationBuilder()
    .SetBasePath(basePath)
    .AddJsonFile("appsettings.json")
    .AddJsonFile($"appsettings.{environmentName}.json", true)
    .AddEnvironmentVariables(); #this seems to be auto-configured in netcoreapp3.1

Environment variable names use a double underscore (__) instead of colon (:).
Ex: "ConnectionStrings__Defaul=X" instead of the appsettings.json "ConnectionStrings { Default="X" }".

Dependency Injection Framework


Service Registrations

Transient: each time the service is requested, a new instance is created.
- Use this by default.

Singleton: one instance of the service will be used for lifetime of the application. I.e. after the first service is instantiated, it will continue to be used for each subsequent request.
- Holds state for the lifetime of the application.
- Only use if you're sure you need it.

Transient inside Singleton: a Singleton service instantiates a Transient service.
- De facto you have two Singleton services, because the outer service only requests the inner service once, resulting in the inner service being the same instance for the lifetime of the outer service.

Scoped: often means one instance of the service per web request. Technically means that the service is tied to the lifetime of a particular object.
Converting From Framework To Core

Notes to self about conversion process
- start with "upgrade-assistant path.csproj"

Web API netcoreapp2.1
- can reference netstandard2.0 libraries, but not netstandard2.1

Microsoft.EntityFrameworkCore
- .Net Framework or .Net Standard only
- EntityFrameworkCore version 2.1.14 (netstandard2.0)
EntityFrameworkCore 2.1.14 limits EntityFrameworkCore.Relational to 2.1.14
- and that does not contain extension method `DbSet<T>.FromRawSql` which I need for stored proc calls
- looks like just calling it `FromSql` instead fixes it

.Net Core vs .Net Standard
- https://docs.microsoft.com/en-us/archive/msdn-magazine/2017/september/net-standard-demystifying-net-core-and-net-standard
```
Here’s how .NET Core and .NET Standard fit into this:

* .NET Core: This is the latest .NET implementation. It’s open source and available for multiple OSes. With .NET Core, you can build cross-platform console apps and ASP.NET Core Web applications and cloud services.

* .NET Standard: This is the set of fundamental APIs (commonly referred to as base class library or BCL) that all .NET implementations must implement. By targeting .NET Standard, you can build libraries that you can share across all your .NET apps, no matter on which .NET implementation or OS they run.
```

having issues
- try clearing NuGet caches