3

I am new to Asp.Net Core and EF. I am developing a simple CRUD from database-end, using the Secrets.json file to hide my connection string credentials.

But I don't know how to reference the file using AddDbContext().

My code so far:

 public class Startup
    {
        public Startup(IConfigurationRoot configuration)
        {
            Configuration = configuration;
        }
        public IConfigurationRoot Configuration { get; }
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();
            services.AddDbContext<POTS.myDBContext>(options => 
                options.UseSqlServer(Configuration.GetConnectionString("myConxStr")));
            services.AddControllers();
        }

When the code runs, I get this error on the AddDbContext<> line

System.ArgumentNullException HResult=0x80004003 Message=Value cannot be null. (Parameter 'connectionString')
Source=Microsoft.EntityFrameworkCore.SqlServer StackTrace: etc etc

I think this is because the code is looking for the parameter in the appsettings.json file, where I don't want the connectionstring to be.

What am I missing?

Fandango68
  • 4,461
  • 4
  • 39
  • 74

2 Answers2

7

Before ASP.NET 6:

You can adding additional Secrets.json file to configuration argument in Startup.cs like below:

public class Startup
{
    public Startup(IConfiguration configuration, IWebHostEnvironment env)
    {
        configuration = new ConfigurationBuilder().SetBasePath(env.ContentRootPath)
        .AddJsonFile("Secrets.json")
        .Build();

        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }
    //...
}

Or add it in Program.cs:

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
    .ConfigureAppConfiguration((hostingContext, config) =>
    {
        var env = hostingContext.HostingEnvironment;

        config.SetBasePath(env.ContentRootPath)
            .AddJsonFile("Secrets.json", optional: true, reloadOnChange: true);

    })
    .ConfigureWebHostDefaults(webBuilder =>
    {
        webBuilder.UseStartup<Startup>();
    });

In ASP.NET 6:

You can add it in Program.cs like below:

var builder = WebApplication.CreateBuilder(args);
builder.Configuration
    .SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile("Secrets.json");

builder.Services.AddDbContext<POTS.myDBContext>(options =>
        options.UseSqlServer(builder.Configuration.GetConnectionString("myConxStr")));

// Add services to the container....
var app = builder.Build();
//....

Then be sure your json file(Secrets.json) must be like below:

{
  "ConnectionStrings": {
    "myConxStr": "xxxxxxx"
  }
}
Rena
  • 30,832
  • 6
  • 37
  • 72
  • I actually didn't need to do anything other than your last suggestion to place the word "ConnectionString" in the secrets.json file. So yeah that alone worked for me. Thanks! – Fandango68 Mar 16 '22 at 05:45
  • Rena, I came back to this again because when deploying to IIS, it's not working. I don't get any data showing. – Fandango68 May 12 '22 at 23:54
  • Since I am using EF, I've read that the SQL Server dataabase login has to have Admin access and be able to create tables, because EF tries to create a resource table in relation to connecting to it. Weird I know. I am trying to deploy using a read-only SQL login, as I am not writing back to the database. – Fandango68 May 12 '22 at 23:55
  • Also, the above by directly referencing secrets.json failed as it's a Connected Services resource. There is no actual secrets.json file in the project's root folder. That would defeat the purpose of hiding the connection string. – Fandango68 May 12 '22 at 23:56
2

In the MS documentation there is a full walk through for app secrets. Of note, even MS suggests this is for non-production use. If you need Startup.cs, the top left there is a dropdown to select v5 or earlier.

Basic Steps for ASP.NET Core 6.0 (refer to link above):

  1. Initialize the secrets within the project directory via cli, a 'UserSecretsId' will be created in the PropertyGroup in the projectName.csproj file:

    dotnet user-secrets init

  2. Create the new secret:

    dotnet user-secrets set "MyDbPassword" "SuperSecretPassword123"

  3. A secrets.json file is created:

    • Windows: %APPDATA%\Microsoft\UserSecrets<user_secrets_id>\secrets.json
    • Mac/Linux: ~/.microsoft/usersecrets/<user_secrets_id>/secrets.json

To use in Program.cs in your case for the ConnectionStrings, scroll down in the documentation to 'String replacement with secrets'

var conStrBuilder = new SqlConnectionStringBuilder(
    builder.Configuration.GetConnectionString("MyDbConnectionWithoutPassword"));
conStrBuilder.Password = builder.Configuration["MyDbPassword"];
var connection = conStrBuilder.ConnectionString;
DenverDave
  • 55
  • 7
  • Thank you. So I *can* use secrets in a production deployment? I thought it was purely for development only – Fandango68 Jun 16 '22 at 01:13
  • 1
    No, this is for non-production use. I have an internal only app and it works for that ;) MS suggests Azure Key Vault (of course) – DenverDave Jun 16 '22 at 16:06