ABP框架入门踩坑-配置User Secrets
配置User Secrets
起因
因为以往习惯在User Secrets中保存连接字符串之类信息,但当我把连接字符串移到secrets.json中后,却发现在迁移过程中会报如下的错误:
简单说,也就是迁移时无法获取到连接字符串信息。
解决方案
在
Qincai.EntityFrameworkCore
项目中,找到QincaiDbContextFactory.cs
文件,修改如下注释处代码。public class QincaiDbContextFactory : IDesignTimeDbContextFactory<QincaiDbContext>
{
public QincaiDbContext CreateDbContext(string[] args)
{
var builder = new DbContextOptionsBuilder<QincaiDbContext>();
//var configuration = AppConfigurations.Get(WebContentDirectoryFinder.CalculateContentRootFolder());
var configuration = AppConfigurations.Get(WebContentDirectoryFinder.CalculateContentRootFolder(), addUserSecrets: true); QincaiDbContextConfigurer.Configure(builder, configuration.GetConnectionString(QincaiConsts.ConnectionStringName)); return new QincaiDbContext(builder.Options);
}
}
经历
这个问题看似解决容易,但还是费了我不少时间才找到原因。
首先,我怀疑是不是secrets.json文件有问题,就把Qincai.Web.Host.csproj
中的UserSecretsId
删掉,重新生成了一个。但难受的是,这下不单是迁移有问题了,连应用都无法启动了,当然报错信息也是无法找到连接字符串。
所以,我开始在StartUp
中找注入配置的代码,然后发现不同于微软模板代码中直接注入IConfiguration
对象的做法,Module Zero自己实现了一个拓展方法IHostingEnvironment.GetAppConfiguration
。其源码如下:
public static IConfigurationRoot GetAppConfiguration(this IHostingEnvironment env)
{
// 这里第三个参数代表是否添加User Secrets
// 可以看到Module Zero默认只在开发环境中添加
return AppConfigurations.Get(env.ContentRootPath, env.EnvironmentName, env.IsDevelopment());
}
这里调用了AppConfigurations
类,注意这个类是定义在Qincai.Core项目中,这是导致问题的关键。
然后,我们来研究一下AppConfigurations
类中的这段代码:
private static IConfigurationRoot BuildConfiguration(string path, string environmentName = null, bool addUserSecrets = false)
{
var builder = new ConfigurationBuilder()
.SetBasePath(path)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
if (!environmentName.IsNullOrWhiteSpace())
{
builder = builder.AddJsonFile($"appsettings.{environmentName}.json", optional: true);
}
builder = builder.AddEnvironmentVariables();
if (addUserSecrets)
{
// 在这里添加了User Secrets
builder.AddUserSecrets(typeof(AppConfigurations).GetAssembly());
}
return builder.Build();
}
乍一看好像没问题,但是注意,我刚才说了AppConfigurations
是属于Qincai.Core
项目,即根据默认的配置,typeof(AppConfigurations).GetAssembly()
获取到的是Qincai.Core.dll
下的程序集。
也就是说,这里添加的User Secrets是根据Qincai.Core.csproj
中定义的UserSecretsId,而不是Qincai.Web.Host.csproj
中定义的。
打开Qincai.Core.csproj
,我们确实注意到有一个UserSecretsId字段,且和Qincai.Web.Host.csproj
中未修改器前的一致。
这里就是Module Zero取巧的地方了,因为在VS中,只有Web项目才能在右键中找到管理用户机密,所以通过两个配置两个相同的UserSecretsId,使其能通过VS的快捷方式修改Qincai.Core
项目的secrets.json文件。
既然找到原因了,那么只需将UserSecretsId恢复成一致即可,痛快地敲下F5,启动成功。
因此注意,一旦在你修改了Qincai.Web.Host.csproj
中的UserSecretsId后,千万不要忘了修改Qincai.Core.csproj
,务必确保两个UserSecretsId一致,不然你再怎么改,程序也是届不到的。
不是完了吗?才怪嘞!!我们的问题是迁移时无法读取User Secrets,以上经历只能说又回到了起点。
到这里,我们已经可以在程序运行时成功读取到User Secrets,但是在数据库迁移过程中,还是会报错:
System.ArgumentNullException: Value cannot be null.
Parameter name: connectionString
让我们打开ef工具的详细输出-v
来看一看,其中有这么一段输出:
Finding DbContext classes...
Finding IDesignTimeDbContextFactory implementations...
Finding application service provider...
Finding IWebHost accessor...
Using environment 'Development'.
Using application service provider from IWebHost accessor on 'Program'.
Finding DbContext classes in the project...
Found DbContext 'QincaiDbContext'.
Using DbContext factory 'QincaiDbContextFactory'.
它提到了QincaiDbContextFactory
这个类,源码如下:
/* This class is needed to run "dotnet ef ..." commands from command line on development. Not used anywhere else */
public class QincaiDbContextFactory : IDesignTimeDbContextFactory<QincaiDbContext>
{
public QincaiDbContext CreateDbContext(string[] args)
{
var builder = new DbContextOptionsBuilder<QincaiDbContext>();
// 注意这里
var configuration = AppConfigurations.Get(WebContentDirectoryFinder.CalculateContentRootFolder();
QincaiDbContextConfigurer.Configure(builder, configuration.GetConnectionString(QincaiConsts.ConnectionStringName));
return new QincaiDbContext(builder.Options);
}
}
看到注释,我们应该就是找对地方了,注意我在代码中标出的位置。它也通过AppConfigurations.Get
来获取配置,但是没有给出AddUserSecrets
参数(默认为false
),而根据此前的代码可知,它没有添加User Secrets。
那么解决方案就很简单了,显式给出AddUserSecrets
参数即可。
var configuration = AppConfigurations.Get(WebContentDirectoryFinder.CalculateContentRootFolder(), addUserSecrets: true);
ABP框架入门踩坑-配置User Secrets的更多相关文章
- ABP框架入门踩坑-配置数据库表前缀
配置数据库表前缀 ABP踩坑记录-目录 本篇其实和ABP关系并不大,主要是EF Core的一些应用-.-. 起因 支持数据库表前缀应该是很多应用中比较常见的功能,而在ABP中并没直接提供这一功能,所以 ...
- ABP框架入门踩坑-添加实体
添加实体 ABP踩坑记录-目录 这里我以问答模块为例,记录一下我在创建实体类过程中碰到的一些坑. 审计属性 具体什么是审计属性我这里就不再介绍了,大家可以参考官方文档. 这里我是通过继承定义好的基类来 ...
- ABP框架入门踩坑-使用MySQL
使用MySQL ABP踩坑记录-目录 起因 因为我自用的服务器只是腾讯云1核1G的学生机,不方便装SQL Server,所以转而MySQL. 这里使用的MySQL版本号为 8.0. 解决方案 删除Qi ...
- 我的微信小程序入门踩坑之旅
前言 更好的阅读体验请:我的微信小程序入门踩坑之旅 小程序出来也有一段日子了,刚出来时也留意了一下.不过赶上生病,加上公司里也有别的事,主要是自己犯懒,就一直没做.这星期一,赶紧趁着这股热乎劲,也不是 ...
- 【ABP框架系列学习】启动配置(5)
ABP提供了在启动时配置模块的基础设施和模型. 1.配置ABP 配置ABP是在模块的PreInitialize方法中完成的,例如: public class SimpleTaskSystemModul ...
- Go ORM框架 - GORM 踩坑指南
今天聊聊目前业界使用比较多的 ORM 框架:GORM.GORM 相关的文档原作者已经写得非常的详细,具体可以看这里,这一篇主要做一些 GORM 使用过程中关键功能的介绍,GORM 约定的一些配置信息说 ...
- 基于ASP.NET MVC的ABP框架入门学习教程
为什么使用ABP 我们近几年陆续开发了一些Web应用和桌面应用,需求或简单或复杂,实现或优雅或丑陋.一个基本的事实是:我们只是积累了一些经验或提高了对,NET的熟悉程度. 随着软件开发经验的不断增加, ...
- 小程序框架MpVue踩坑日记(一)
小程序也做了几个小功能模块了,总觉得需要总结一下,踩坑什么的还是得记录一下啊. 好吧,其实是为了方便回顾 首先,说到小程序框架,大家都知道wepy,不过,我是没用过 美团开发团队到mpvue到是个实在 ...
- ABP框架入门
技术要求 在开始使用 ABP 框架之前,您需要在计算机上安装一些工具. IDE/编辑器 本书假设您使用的是Visual Studio 2022(支持 .NET 6.0 的 v10.0)或更高版本.如果 ...
随机推荐
- 【校招面试 之 C/C++】第1题 为什么优先使用构造函数的初始化列表
1.首先看一个例子: #include<iostream> using namespace std; class Test1 { public: Test1() // 无参构造函数 { c ...
- 源码安装php时出现configure: error: xml2-config not found. Please check your libxml2 installation
1.检查是否安装了libxml 包 > rpm -qa|grep libxml2 2.如果没有则安装 > yum install libxml2 > yum install libx ...
- Django之XSS攻击
一.什么是XSS攻击 xss攻击:----->web注入 xss跨站脚本攻击(Cross site script,简称xss)是一种“HTML注入”,由于攻击的脚本多数时候是跨域的,所以称 ...
- Nginx下SSL证书设置和反向代理
上来就贴代码: server { listen ; server_name **.****.net; #填写绑定证书的域名 ssl on; ssl_certificate /opt/nginx-/co ...
- mupdf编译snprintf冲突问题
mupdf-1.6-source\thirdparty\jbig2dec\config_win32.h //# define snprintf _snprintf
- ELMAH 使用
之前大部分系统日志记录是使用log4net.ObjectGuy Framework.NLog 等工具记录到文本或数据库. 更强大的工具可以使用 ELMAH. ELMAH(The Error Loggi ...
- 521. Longest Uncommon Subsequence I
static int wing=[]() { std::ios::sync_with_stdio(false); cin.tie(NULL); ; }(); class Solution { publ ...
- Linux命令:sed
简介 sed 是一种在线编辑器,它一次处理一行内容.处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”(pattern space),接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的 ...
- UVa 11464 Even Parity (二进制法枚举)
题意:给你一个n*n的01矩阵,让你把最少的0变成1,使得每个元素的上,下,左,右的元素(如果有的话)之和均为偶数. 析:最好想的的办法就是暴力,就是枚举每个数字是变还是不变,但是...时间复杂度也太 ...
- MySQL之SQL语句零碎总结
一.MySQL中有个ifnull函数,跟Oracle的nvl类似,用法如下: select* from Ta t where ifnull(pro, 0) < 100; 解释:当pro是null ...