创建一个从用户秘密获取连接字符串的DbContextFactory [英] Creating a DbContextFactory that gets the connection string from user-secrets
问题描述
使用一个 WebApi
项目和一个单独的 Data
项目(包含实体框架实现)来开发DotNetCore解决方案。我们一直在升级库,因为它们出来了,所以我们使用了所有最新的Core东西。
Working on a DotNetCore solution with a WebApi
project and a separate Data
project that houses the Entity Framework implementation. We've been upgrading libraries as they come out, so we're using all of the newest Core stuff.
在 Data $中c $ c>项目,我们创建了一个
ApplicationDbContextFactory
以便创建迁移(需要无参数构造函数)。由于添加迁移时无参数构造函数的限制,您不能注入 IOptions<>
来轻松访问 appsettings.json
值。我们最终使用了 ConfigurationBuilder
插入 WebApi
的 appsettings.json
文件。
In the Data
project, we created an ApplicationDbContextFactory
in order to create migrations (needs a parameterless constructor). Due to the parameterless constructor constraint when adding a migration, you can't inject IOptions<>
to easily access appsettings.json
values. We ended up using a ConfigurationBuilder
to pull in the WebApi
's appsettings.json
file(s).
我们最近更改了 ApplicationDbContextFactory
来加入用户秘密
。这样,每个开发人员都可以使用自定义的连接字符串,而不必忽略文件或记住不要提交任何内容。
We recently changed the ApplicationDbContextFactory
to also pull in user-secrets
. This allows each developer to use a custom connection string without having to ignore a file or remember to not commit something.
由于进行了此更改,因此使用 dotnet ef迁移添加MIGRATION_NAME
在命令行中效果很好。但是,现在在Visual Studio的Package Manager控制台中使用 add-migration MIGRATION_NAME
似乎已被破坏,并出现以下错误:
Since making this change, using dotnet ef migrations add MIGRATION_NAME
works just fine in command line. However, using add-migration MIGRATION_NAME
in Visual Studio's Package Manager Console now appears to be broken with the following error:
add-migration:使用 1作为参数调用 Substring的异常:
StartIndex不能小于零。参数名称:startIndex在
行: 1个字符:1 + add-migration测试+ ~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo:未指定:(:) [Add-Migration], MethodInvocationException
+ FullyQualifiedErrorId:ArgumentOutOfRangeException,Add-Migration
add-migration : Exception calling "Substring" with "1" argument(s): "StartIndex cannot be less than zero. Parameter name: startIndex" At line:1 char:1 + add-migration TESTING + ~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [Add-Migration], MethodInvocationException + FullyQualifiedErrorId : ArgumentOutOfRangeException,Add-Migration
我尝试了一些命令变体,看是否需要要指定上下文(除其他事项外),但似乎没有任何解决此错误的方法。它似乎永远不会绕过 ApplicationDbContextFactory
中的构造函数。
I tried a few variations of the command to see if it needed the context to be specified (among other things), but nothing seemed to get around this error. It never seems to get past the constructor in ApplicationDbContextFactory
.
这是我指的代码:
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options;
using Models.Domain.Settings;
using System;
using System.Diagnostics;
namespace Data
{
public class ApplicationDbContextFactory : IDbContextFactory<ApplicationDbContext>
{
private readonly SolutionSettings _settings;
// In order to use 'add-migration' in Visual Studio, you have to have a parameterless constructor.
// Otherwise you get "No parameterless constructor defined for this object." when creating a migration.
public ApplicationDbContextFactory()
{
}
public ApplicationDbContextFactory(IOptions<SolutionSettings> settings)
{
_settings = settings.Value;
}
public ApplicationDbContext Create(DbContextFactoryOptions options)
{
// If the IOptions signature was hit, we can just pull the dbconnection from settings
if (_settings != null && _settings.DbConnection != null)
{
var optionsBuilder = new DbContextOptionsBuilder<ApplicationDbContext>()
.UseSqlServer(_settings.DbConnection, opts => {
opts.EnableRetryOnFailure();
opts.MigrationsAssembly("Data");
});
return new ApplicationDbContext(optionsBuilder.Options);
}
else
{
// Otherwise, we have to get the settings manually...
return Create(options.ContentRootPath, options.EnvironmentName);
}
}
private ApplicationDbContext Create(string basePath, string environmentName)
{
// HACK: To pull from WebApi\appsettings.json
basePath = basePath.Replace("Data", "WebApi");
Console.Write($"PATH & ENV: {basePath}, {environmentName}" + Environment.NewLine);
// Pull in the WebApi\appsettings.json files, apply user secrets
var builder = new ConfigurationBuilder()
.SetBasePath(basePath)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{environmentName.ToLower()}.json", optional: true, reloadOnChange: true)
// This needs to match the UserSecretsId value in the WebApi.csproj
// Also added a UserSecretsId key with the same value to Data.csproj to suppress a warning
// Adding this was the only way it would actually override values with user-secret values
.AddUserSecrets("USER_SECRETS_ID")
.AddEnvironmentVariables();
var config = builder.Build();
var connectionString = config["SolutionSettings:DbConnection"];
Console.Write($"CONNECTION STRING: {connectionString}" + Environment.NewLine);
return Create(connectionString);
}
private ApplicationDbContext Create(string connectionString)
{
if (string.IsNullOrEmpty(connectionString))
throw new ArgumentException(
$"{nameof(connectionString)} is null or empty.",
nameof(connectionString));
var optionsBuilder = new DbContextOptionsBuilder<ApplicationDbContext>()
.UseSqlServer(connectionString, options => {
options.EnableRetryOnFailure();
options.MigrationsAssembly("Data");
});
return new ApplicationDbContext(optionsBuilder.Options);
}
}
}
在解决此问题时,我添加了 opts.EnableRetryOnFailure();
和 opts.MigrationsAssembly( Data);
,但是我不知道它们在这种情况下没有任何作用。
As a side note; while troubleshooting this I added opts.EnableRetryOnFailure();
and opts.MigrationsAssembly("Data");
, but I don't know that they make any difference in this context.
我的问题:
- 这最初是在Core的RC时代实施的,可能有些过时了。创建迁移时,是否有更好的方法来完成对用户秘密值的提取?
- 有人知道为什么我们会在Visual Studio的Package Manager控制台中收到该错误吗?
推荐答案
自您发布以来已经很长时间了,但是我只是遇到了这个错误并找出了原因(即使它使
It's been a long time since you posted it, but I've just had this error and found out the reason (even though it makes no sense)
问题出在
console.Write($"CONNECTION STRING: {connectionString}" + Environment.NewLine);
如果在连接字符串后移动冒号,它将起作用。
我不知道为什么插值中的冒号会导致此错误
If you romove the colon after CONNECTION STRING it works. I have no idea why the colon in the interpolation is causing this error
这篇关于创建一个从用户秘密获取连接字符串的DbContextFactory的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!