skip to Main Content

EDIT: This question has been significantly restructured, now I’ve figured out a bit more of the problem and this should clarify things.

I am following this tutorial: https://learn.microsoft.com/en-us/azure/app-service/tutorial-dotnetcore-sqldb-app

I’ve deployed my own multiproject app, which works, but I can’t get the connection string working properly. For some reason, it only works if I hardcode the connection string into the OnConfiguring method of my DBContext class. Otherwise, it throws an error.

Like so:

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder
        .UseSqlServer(
                "Nasty hard coded azure connection string",
                providerOptions => { providerOptions.EnableRetryOnFailure(); });
    } 

However, obviously, i want to get the connection string from a configuration file or environment variable.

Prior to deploying, I had the following. An extension method for IServiceColleciton which sets up the connection string:

public static void ConfigureSqlContext(this IServiceCollection services,
    IConfiguration configuration) =>
    services.AddDbContext<PeakedDbContext>(opts =>
 opts.UseSqlServer(configuration.GetConnectionString("defaultConnection")));

then this method is called in program.cs. A pretty normal setup.

And I also set up an IDesignTimeDBContextFactory like so:

 public class RepositoryContextFactory : IDesignTimeDbContextFactory<PeakedDbContext>
    {
        public PeakedDbContext CreateDbContext(string[] args)
        {
            var configuration = new ConfigurationBuilder()
            .SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile("appsettings.json")
            .Build();
            var builder = new DbContextOptionsBuilder<PeakedDbContext>()
            .UseSqlServer(configuration.GetConnectionString("defaultConnection"));
            return new PeakedDbContext(builder.Options);
        }
    }

Both my appsettings.json AND the Azure App Service configuration have the same name "defaultConnection".

As far as I can tell this is the approach recommended here: https://learn.microsoft.com/en-us/ef/core/cli/dbcontext-creation?tabs=dotnet-core-cli

I have also tried adding an empty constructor for my DBContext. (Not sure how this affects things as I have other DIs on my DBContext constructor. My DBContext consructors are getting a bit out of hand:

    public PeakedDbContext()
    {
    }

    public PeakedDbContext(DbContextOptions options) : base(options)
    {
    }

    public PeakedDbContext(DbContextOptions options, ICurrentUserService currentUserService) : base(options)
    {
        _currentUserService = currentUserService;
    }

According the the second link, above, I shouldn’t need OnConfiguring method in my DBContext… and even if I do, what is the correct way to pass access to configuration.GetConnectionString, instead of hardcoding the connection string? Should I just add yet another DBContext constructor with the config injected? However, it ONLY works if I have the onconfiguring method. Neither the contextfactory nor the extension method setup are being used by azure app service.

Shouldn’t it use the designtime factory or the hostconfiguration extension method I’ve set up above? What is the right way to use _configuration.GetConnectionString("defaultConnection") so that it works both locally and on Azure Deployment?

Update:
Still no luck. I tried adding the database connection string as an environment variable on azure like so:
enter image description here

and then updating all my reference to getconnection string – in program.cs, IDesignFactory and OnConfiguring – like so:

Environment.GetEnvironmentVariable("PeakedDbConn")

This continues to work locally. But When deploying to Azure it claims the connection string in null… so it’s not seeing this variable. Nor can I find any code that will access the defaultConnection from the image. Which is strange, because it accesses the SECRET variable just fine.

2

Answers


  1. Chosen as BEST ANSWER

    Ok so it turned out to be GitHub actions that was the problem. The tutorial I followed in the first link doesn't mention this, perhaps because it's a single project api... not exactly sure.

    The tutorial uses github actions to build and deploy the app, but for me, during the build it fails saying there is no connection string. This is because GitHub build process doesn't have access to either your local or the azure environment variable.

    So I had to go into setting on my github repo and on the left click on secrets and variables < actions.

    Click create a new Repository Secret, give it the same name as your environment variable i.e. PEAKEDDBCONN for me. Then, give it a value. I just used my local host string, but I guess you could type 'monkeynuts' in here if you wanted, it just needs to not be null.

    Then you need to add a line to your workflow yaml file, the same one the tutorial talks about, to tell it about the environment variable. I added it like so:

    jobs:
      build:
        runs-on: ubuntu-latest
        env:
          PEAKEDDBCONN: ${{ secrets.PEAKEDDBCONN }}
    

    Then it all builds nicely and works.

    For anybody who it helps, I decided to blog this whole setup: https://garyfrewin.hashnode.dev/setting-up-an-entity-framework-core-web-api-on-azure-with-sqlserver-a-step-by-step-guide-for-hobby-projects


  2. I have followed the same code which you have provided with few changes.

    Check the below steps to get the Connection string from appsettings.json and override the value if Azure App Connection String has been set.

    As you are using .NET Core 6, I have set all the Configurations in Program.cs itself.

    My Program.cs

    builder.Services.AddDbContext<MyDatabaseContext>(options =>
                        options.UseSqlServer(builder.Configuration.GetConnectionString("MyDbConnection")));
    builder.Configuration.AddEnvironmentVariables();
    

    Same Connection String name must exist in both Local and Azure App Connection Strings.

    My appsettings.json

    {
      "Logging": {
        "LogLevel": {
          "Default": "Information",
          "Microsoft.AspNetCore": "Warning"
        }
      },
      "AllowedHosts": "*",
      "ConnectionStrings": {
        "MyDbConnection": "Dummy Connection String"
      }
    }
    

    Azure App Connection String:
    enter image description here

    • To check if we are getting the Connection String Value, I have written code in Controller.
     private readonly IConfiguration Configuration;
     public HomeController(ILogger<HomeController> logger,IConfiguration config)
            {
                _logger = logger;
                Configuration = config;
            }
           
             public IActionResult Index()
            {
                var myconnStr = Configuration.GetConnectionString("MyDbConnection");           
                ViewBag.myconnStr = myconnStr;           
                return View();
            }
    

    My .csproj file :

    <Project Sdk="Microsoft.NET.Sdk.Web">
    
      <PropertyGroup>
        <TargetFramework>net6.0</TargetFramework>
        <Nullable>enable</Nullable>
        <ImplicitUsings>enable</ImplicitUsings>
      </PropertyGroup>
    
      <ItemGroup>
        <PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.2" />
        <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.2" />
        <PackageReference Include="Microsoft.Extensions.Configuration.AzureAppConfiguration" Version="5.2.0" />
        <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" />
      </ItemGroup>
    
    </Project>
    

    Local Output:

    enter image description here

    Deployed App Output:
    enter image description here

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search