Обновлено: этот вопрос был значительно реструктурирован, теперь я немного разобрался в проблеме, и это должно прояснить ситуацию.
Я следую этому руководству: https://learn.microsoft.com/en-us/azure/app-service/tutorial-dotnetcore-sqldb-app
Я развернул свое собственное многопроектное приложение, которое работает, но я не могу заставить строку подключения работать должным образом. По какой-то причине это работает, только если я жестко запрограммирую строку подключения в методе OnConfiguring моего класса DBContext. В противном случае выдает ошибку.
Вот так:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
.UseSqlServer(
"Nasty hard coded azure connection string",
providerOptions => { providerOptions.EnableRetryOnFailure(); });
}
Однако, очевидно, я хочу получить строку подключения из файла конфигурации или переменной среды.
До развертывания у меня было следующее. Метод расширения для IServiceColleciton, который устанавливает строку подключения:
public static void ConfigureSqlContext(this IServiceCollection services,
IConfiguration configuration) =>
services.AddDbContext<PeakedDbContext>(opts =>
opts.UseSqlServer(configuration.GetConnectionString("defaultConnection")));
то этот метод вызывается в program.cs. Вполне нормальная установка.
И я также настроил IDesignTimeDBContextFactory следующим образом:
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);
}
}
И мой файл appsettings.json, и конфигурация службы приложений Azure имеют одно и то же имя defaultConnection.
Насколько я могу судить, этот подход рекомендуется здесь: https://learn.microsoft.com/en-us/ef/core/cli/dbcontext-creation?tabs=dotnet-core-cli
Я также попытался добавить пустой конструктор для моего DBContext. (Не уверен, как это повлияет на вещи, поскольку у меня есть другие DI в моем конструкторе DBContext. Мои конструкторы DBContext немного выходят из-под контроля:
public PeakedDbContext()
{
}
public PeakedDbContext(DbContextOptions options) : base(options)
{
}
public PeakedDbContext(DbContextOptions options, ICurrentUserService currentUserService) : base(options)
{
_currentUserService = currentUserService;
}
Согласно второй ссылке выше, мне не нужен метод OnConfiguring в моем DBContext... и даже если я это сделаю, как правильно передать доступ к configuration.GetConnectionString вместо жесткого кодирования строки подключения? Должен ли я просто добавить еще один конструктор DBContext с введенной конфигурацией? Однако это работает ТОЛЬКО, если у меня есть метод onconfiguring. Ни контекстная фабрика, ни настройка метода расширения не используются службой приложений Azure.
Разве он не должен использовать фабрику времени разработки или метод расширения конфигурации хоста, который я установил выше? Как правильно использовать _configuration.GetConnectionString("defaultConnection"), чтобы он работал как локально, так и в развертывании Azure?
Обновлять: Все равно не повезло. Я попытался добавить строку подключения к базе данных в качестве переменной среды на Azure следующим образом:
а затем обновить всю мою ссылку на строку getconnection - в program.cs, IDesignFactory и OnConfiguring - вот так:
Environment.GetEnvironmentVariable("PeakedDbConn")
Это продолжает работать локально. Но при развертывании в Azure он утверждает, что строка подключения имеет значение null... поэтому эта переменная не отображается. Я также не могу найти код, который будет получать доступ к defaultConnection из изображения. Что странно, потому что он прекрасно обращается к переменной SECRET.
В Program.cs
добавьте builder.Services.AddDbContext<MyDatabaseContext>(options => options.UseSqlServer(builder.Configuration.GetConnectionString("MyDbConnection"))); builder.Configuration.AddEnvironmentVariables();
и проверьте один раз.
Спасибо, у меня уже есть бит AddDBContext в моем методе расширения, но я попытался добавить AddEnvVariables в program.cs и IDesignTimeFactory, это не имело никакого значения. Он по-прежнему говорит, что нет провайдера для DBContext.
Я следовал тому же коду, который вы предоставили, с небольшими изменениями.
Выполните следующие шаги, чтобы получить строку подключения из appsettings.json
и переопределить значение, если Azure App Connection String
было установлено.
Поскольку вы используете .NET Core 6
, я установил все конфигурации в самом Program.cs
.
Мой Program.cs
builder.Services.AddDbContext<MyDatabaseContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("MyDbConnection")));
builder.Configuration.AddEnvironmentVariables();
Одно и то же имя Connection String
должно существовать как в Local
, так и в Azure App Connection Strings
.
Мой appsettings.json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"MyDbConnection": "Dummy Connection String"
}
}
Строка подключения к приложению Azure:
Connection String
, я написал код в 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();
}
Мой .csproj
файл:
<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>
Локальный вывод:
Вывод развернутого приложения:
Итак, проблема оказалась в действиях GitHub. В учебнике, которому я следовал по первой ссылке, это не упоминается, возможно, потому, что это API одного проекта... не совсем уверен.
В учебнике используются действия github для сборки и развертывания приложения, но для меня во время сборки происходит сбой, сообщающий об отсутствии строки подключения. Это связано с тем, что процесс сборки GitHub не имеет доступа ни к вашей локальной переменной, ни к переменной среды Azure.
Поэтому мне пришлось зайти в настройки моего репозитория github и щелкнуть левой кнопкой мыши секреты и переменные < действия.
Нажмите «Создать новый секрет репозитория», дайте ему то же имя, что и ваша переменная среды, например, PEAKEDDBCONN для меня. Затем присвойте ему значение. Я просто использовал свою локальную строку хоста, но я думаю, что вы можете ввести здесь «monkeynuts», если хотите, просто она не должна быть нулевой.
Затем вам нужно добавить строку в файл yaml вашего рабочего процесса, ту же самую, о которой говорится в руководстве, чтобы сообщить ему о переменной среды. Я добавил это так:
jobs:
build:
runs-on: ubuntu-latest
env:
PEAKEDDBCONN: ${{ secrets.PEAKEDDBCONN }}
Тогда все прекрасно строится и работает.
Для всех, кому это поможет, я решил опубликовать всю эту настройку в блоге: https://garyfrewin.hashnode.dev/setting-up-an-entity-framework-core-web-api-on-azure-with-sqlserver-a-step-by-step-guide-for-hobby- проекты
Какую структуру вы используете? Пожалуйста, поделитесь своим
.csproj
файлом один раз.