配置User Secrets

ABP踩坑记录-目录

起因

因为以往习惯在User Secrets中保存连接字符串之类信息,但当我把连接字符串移到secrets.json中后,却发现在迁移过程中会报如下的错误:

简单说,也就是迁移时无法获取到连接字符串信息。

解决方案

  1. 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的更多相关文章

  1. ABP框架入门踩坑-配置数据库表前缀

    配置数据库表前缀 ABP踩坑记录-目录 本篇其实和ABP关系并不大,主要是EF Core的一些应用-.-. 起因 支持数据库表前缀应该是很多应用中比较常见的功能,而在ABP中并没直接提供这一功能,所以 ...

  2. ABP框架入门踩坑-添加实体

    添加实体 ABP踩坑记录-目录 这里我以问答模块为例,记录一下我在创建实体类过程中碰到的一些坑. 审计属性 具体什么是审计属性我这里就不再介绍了,大家可以参考官方文档. 这里我是通过继承定义好的基类来 ...

  3. ABP框架入门踩坑-使用MySQL

    使用MySQL ABP踩坑记录-目录 起因 因为我自用的服务器只是腾讯云1核1G的学生机,不方便装SQL Server,所以转而MySQL. 这里使用的MySQL版本号为 8.0. 解决方案 删除Qi ...

  4. 我的微信小程序入门踩坑之旅

    前言 更好的阅读体验请:我的微信小程序入门踩坑之旅 小程序出来也有一段日子了,刚出来时也留意了一下.不过赶上生病,加上公司里也有别的事,主要是自己犯懒,就一直没做.这星期一,赶紧趁着这股热乎劲,也不是 ...

  5. 【ABP框架系列学习】启动配置(5)

    ABP提供了在启动时配置模块的基础设施和模型. 1.配置ABP 配置ABP是在模块的PreInitialize方法中完成的,例如: public class SimpleTaskSystemModul ...

  6. Go ORM框架 - GORM 踩坑指南

    今天聊聊目前业界使用比较多的 ORM 框架:GORM.GORM 相关的文档原作者已经写得非常的详细,具体可以看这里,这一篇主要做一些 GORM 使用过程中关键功能的介绍,GORM 约定的一些配置信息说 ...

  7. 基于ASP.NET MVC的ABP框架入门学习教程

    为什么使用ABP 我们近几年陆续开发了一些Web应用和桌面应用,需求或简单或复杂,实现或优雅或丑陋.一个基本的事实是:我们只是积累了一些经验或提高了对,NET的熟悉程度. 随着软件开发经验的不断增加, ...

  8. 小程序框架MpVue踩坑日记(一)

    小程序也做了几个小功能模块了,总觉得需要总结一下,踩坑什么的还是得记录一下啊. 好吧,其实是为了方便回顾 首先,说到小程序框架,大家都知道wepy,不过,我是没用过 美团开发团队到mpvue到是个实在 ...

  9. ABP框架入门

    技术要求 在开始使用 ABP 框架之前,您需要在计算机上安装一些工具. IDE/编辑器 本书假设您使用的是Visual Studio 2022(支持 .NET 6.0 的 v10.0)或更高版本.如果 ...

随机推荐

  1. 【校招面试 之 C/C++】第28题 C++ 内存泄漏的检查

    1.memwatch的使用 (1)首先去官网上下载源码: http://www.linkdata.se/sourcecode/memwatch/ 解压得到memwatch.c以及memwatch.h两 ...

  2. Microsoft SQL Server, 错误:4064的解决方法 (转载)

    SQL SERVER – Fix : Error: 4064 – Cannot open user default database. Login failed. Login failed for u ...

  3. [leetcode]112. Path Sum路径和(是否有路径)

    Given a binary tree and a sum, determine if the tree has a root-to-leaf path such that adding up all ...

  4. 利用redis完成自动补全搜索功能(二)

    前面介绍了自动完成的大致思路,现在把搜索次数的功能也结合上去.我采用的是hash表来做的,当然也可以在生成分词的时候,另外一个有序集合来维护排序, 然后2个有序集合取交集即可.这里介绍hash的方式来 ...

  5. JSF控件的immediate属性和页面生命周期

    JSF中的控件基本都有immediate属性,对于这个属性的使用总结如下,更详细内容可参考Oracle官方文档. 1,为了更好的理解immediate属性,先看一下JSF页面的生命周期: JSF页面的 ...

  6. ubuntu下常用操作

    屏幕截图: 可以用ubuntu自带的截图软件:gnome-screenshot. 该工具截图区域并且复制到剪切板命令为  gnome-screenshot -c -a,可以给该命令添加快捷方式,alt ...

  7. 22条常用JavaScript开发小技巧

    1.使用var声明变量 如果给一个没有声明的变量赋值,默认会作为一个全局变量(即使在函数内赋值).要尽量避免不必要的全局变量. 2.行尾使用分号 虽然JavaScript允许省略行尾的分号,但是有时不 ...

  8. 如何使用webpack打包前端项目

    webpack概述 随着前端体积越来越大,功能越来越丰富,这时候就需要将前端工程化,而 webpack就是用于将前端各种文件打包起来. 一个简单的webpack应该包含以下几个概念 · 入口起点 · ...

  9. 2018.09.28 bzoj3743: [Coci2015]Kamp(树形dp)

    传送门 这是一道很有意思的题. 我们把所有的关键点都提出来,当成一棵有边权的虚树. 然后发现虚树上除最后不回到虚根的那条路径外外每条边都会被走两遍. 显然要让答案最优,不走的路径应该在虚树的直径上,于 ...

  10. 2018.09.08 NOIP模拟 division(状压dp)

    这么sb的题考场居然写挂了2233. 假设n=∏iaiki" role="presentation" style="position: relative;&qu ...