从 Dapper 连接但从 EF 6 工作的神秘身份验证错误 - 相同的 ConnectionString
Mysterious authentication error connecting from Dapper but works from EF 6 - same ConnectionString
我们有 IoC 加载的服务和存储库。
/* registration in the service class for repository */
container.Register<IContainerRepository, ContainerRepository>();
/* registration in GUI app from service class and Form class for constructor injection usage */
container.Register<IContainerService, ContainerService>();
container.Register<rfrmContainerList, rfrmContainerList>();
所以我们有 ContainerRepository
用于数据访问和 ContainerService
用于业务逻辑。
ContainerRepository
使用 EF6 和 Dapper(基本上 EF6 用于简单查询和 insert/update/delete 方法,而我们使用 Dapper 用于针对复杂连接数据的 运行 优化查询)。每个存储库都有 IoC 在 class 构造函数中传递的 EF6 上下文。 Dapper 始终从上下文中获取 ConnectionString:
var testItem = Context.Container.FirstOrDefault();
using (SqlConnection connection = new SqlConnection(Context.Database.Connection.ConnectionString))
{
var builder = new SqlBuilder();
...
var items = connection.Query<ContainerDto>(sql.RawSql, sql.Parameters);
}
构造函数注入注入的ContainerService
:
private readonly IContainerService _containerService;
public rfrmContainerList(IContainerService containerService)
{
_containerService = containerService ?? throw new ArgumentNullException(nameof(containerService));
}
现在一切都已设置,所以我希望如果 Dapper 使用与 EF6 相同的 ConnectionString,它将使用相同的身份验证,对吗?
没有。虽然 var testItem = Context.Container.FirstOrDefault();
成功 returns 预期结果 Dapper 在 connection.Query<>
失败并抛出异常说 Login failed for user 'username'
(用户名替换为我的测试用户的实际登录名)。
所以经过多次测试和尝试,我终于定位了主要问题,它在 IoC 中。
/* This query will return successfully */
var localContainerService = IoC.Resolve<IContainerService>();
var container = localContainerService.ListContainers(new Model.QueryParams.DesktopApp.Operation.ContainerListQueryParams() { StatusDateFrom = new DateTime(2019, 8, 1), StatusDateTo = DateTime.Now.Date });
/* This query will fail with authentication */
var container2 = _containerService.ListContainers(new Model.QueryParams.DesktopApp.Operation.ContainerListQueryParams() { StatusDateFrom = new DateTime(2019, 8, 1), StatusDateTo = DateTime.Now.Date });
因此,使用本地解析的服务对象的第一个查询运行没有任何问题,从上下文中获取 ConnectionString 和 connection.Query<ContainerDto>(sql.RawSql, sql.Parameters)
returns 预期结果。
使用构造函数注入服务的第二个查询在同一行失败说 "Login failed for user 'username'"。
奇怪,但 EF6 查询 var testItem = Context.Container.FirstOrDefault();
适用于这两种情况。
有人遇到过类似的问题吗?我已经检查了我所有的 IoC 注册,但无法弄清楚为什么会发生这种奇怪的行为。
在多种情况下这将不起作用。好消息是您一开始就不应该使用两个单独的 SqlConnections。只需使用 Dapper/ADO.NET 的 DbContext 的 SqlConnection。 DbContext 将清理 SqlConnection,您甚至不需要额外的 using
块。
就像这样:
class MyDb : DbContext
{
public SqlConnection GetConnection()
{
var con = (SqlConnection)Database.Connection;
if (con.State != System.Data.ConnectionState.Open)
{
con.Open();
}
return con;
}
// . . .
}
如果您使用 SQL 身份验证 (UId / Pwd),那么当您使用 context.Database.Connection.ConnectionString
时,EF 不会 泄露密码。例如,将其输出到控制台,您会得到如下内容:
"Data Source=QH10373138\DEV2008R2;Initial Catalog=Spikes;uid=sqladmin;MultipleActiveResultSets=True"
我的初始连接字符串包含“;pwd=HeyYouShouldntSeeThi$”
如果您使用 Windows 身份验证,应该 有效。
虽然对 David 的回答 +1,但如果您需要做一些棘手的事情,请使用 EF 的 DbConnection。
我还会看看这些问题是否可以通过更好的 EF 查询来解决,例如利用 Select
的投影来获取与 EagerLoading 相关的详细信息,或者寻找延迟加载的陷阱。就个人而言,在使用 NHibernate 处理大量项目之后,当 EF(4) 除了最琐碎的场景外,对任何事情都毫无用处时,到现在几乎完全使用 EF 6,我还没有找到我需要的场景像 Dapper 来解决最坏的情况,即通过有界上下文引入优化的实体模型。这很少见,当它被使用时,它类似于支持批量操作。变通办法的风险是它们成为隐藏设计问题并增加维护复杂性的拐杖。默认方法是,如果 EF 看起来很慢,则编写一个 Dapper 替代方案,而不是解决 EF 代码编写方式中可能存在的简单低效问题。
感谢这些回答,我要添加另一个:ConnectionString 必须包含 Persist Security Info=true
并且它再次起作用。
不过我更喜欢@David 的解决方案。
我们有 IoC 加载的服务和存储库。
/* registration in the service class for repository */
container.Register<IContainerRepository, ContainerRepository>();
/* registration in GUI app from service class and Form class for constructor injection usage */
container.Register<IContainerService, ContainerService>();
container.Register<rfrmContainerList, rfrmContainerList>();
所以我们有 ContainerRepository
用于数据访问和 ContainerService
用于业务逻辑。
ContainerRepository
使用 EF6 和 Dapper(基本上 EF6 用于简单查询和 insert/update/delete 方法,而我们使用 Dapper 用于针对复杂连接数据的 运行 优化查询)。每个存储库都有 IoC 在 class 构造函数中传递的 EF6 上下文。 Dapper 始终从上下文中获取 ConnectionString:
var testItem = Context.Container.FirstOrDefault();
using (SqlConnection connection = new SqlConnection(Context.Database.Connection.ConnectionString))
{
var builder = new SqlBuilder();
...
var items = connection.Query<ContainerDto>(sql.RawSql, sql.Parameters);
}
构造函数注入注入的ContainerService
:
private readonly IContainerService _containerService;
public rfrmContainerList(IContainerService containerService)
{
_containerService = containerService ?? throw new ArgumentNullException(nameof(containerService));
}
现在一切都已设置,所以我希望如果 Dapper 使用与 EF6 相同的 ConnectionString,它将使用相同的身份验证,对吗?
没有。虽然 var testItem = Context.Container.FirstOrDefault();
成功 returns 预期结果 Dapper 在 connection.Query<>
失败并抛出异常说 Login failed for user 'username'
(用户名替换为我的测试用户的实际登录名)。
所以经过多次测试和尝试,我终于定位了主要问题,它在 IoC 中。
/* This query will return successfully */
var localContainerService = IoC.Resolve<IContainerService>();
var container = localContainerService.ListContainers(new Model.QueryParams.DesktopApp.Operation.ContainerListQueryParams() { StatusDateFrom = new DateTime(2019, 8, 1), StatusDateTo = DateTime.Now.Date });
/* This query will fail with authentication */
var container2 = _containerService.ListContainers(new Model.QueryParams.DesktopApp.Operation.ContainerListQueryParams() { StatusDateFrom = new DateTime(2019, 8, 1), StatusDateTo = DateTime.Now.Date });
因此,使用本地解析的服务对象的第一个查询运行没有任何问题,从上下文中获取 ConnectionString 和 connection.Query<ContainerDto>(sql.RawSql, sql.Parameters)
returns 预期结果。
使用构造函数注入服务的第二个查询在同一行失败说 "Login failed for user 'username'"。
奇怪,但 EF6 查询 var testItem = Context.Container.FirstOrDefault();
适用于这两种情况。
有人遇到过类似的问题吗?我已经检查了我所有的 IoC 注册,但无法弄清楚为什么会发生这种奇怪的行为。
在多种情况下这将不起作用。好消息是您一开始就不应该使用两个单独的 SqlConnections。只需使用 Dapper/ADO.NET 的 DbContext 的 SqlConnection。 DbContext 将清理 SqlConnection,您甚至不需要额外的 using
块。
就像这样:
class MyDb : DbContext
{
public SqlConnection GetConnection()
{
var con = (SqlConnection)Database.Connection;
if (con.State != System.Data.ConnectionState.Open)
{
con.Open();
}
return con;
}
// . . .
}
如果您使用 SQL 身份验证 (UId / Pwd),那么当您使用 context.Database.Connection.ConnectionString
时,EF 不会 泄露密码。例如,将其输出到控制台,您会得到如下内容:
"Data Source=QH10373138\DEV2008R2;Initial Catalog=Spikes;uid=sqladmin;MultipleActiveResultSets=True"
我的初始连接字符串包含“;pwd=HeyYouShouldntSeeThi$”
如果您使用 Windows 身份验证,应该 有效。
虽然对 David 的回答 +1,但如果您需要做一些棘手的事情,请使用 EF 的 DbConnection。
我还会看看这些问题是否可以通过更好的 EF 查询来解决,例如利用 Select
的投影来获取与 EagerLoading 相关的详细信息,或者寻找延迟加载的陷阱。就个人而言,在使用 NHibernate 处理大量项目之后,当 EF(4) 除了最琐碎的场景外,对任何事情都毫无用处时,到现在几乎完全使用 EF 6,我还没有找到我需要的场景像 Dapper 来解决最坏的情况,即通过有界上下文引入优化的实体模型。这很少见,当它被使用时,它类似于支持批量操作。变通办法的风险是它们成为隐藏设计问题并增加维护复杂性的拐杖。默认方法是,如果 EF 看起来很慢,则编写一个 Dapper 替代方案,而不是解决 EF 代码编写方式中可能存在的简单低效问题。
感谢这些回答,我要添加另一个:ConnectionString 必须包含 Persist Security Info=true
并且它再次起作用。
不过我更喜欢@David 的解决方案。