如果运行我的服务的用户无权访问数据库,则EF将失败并出现以下异常:
System.Data.Entity.Core.ProviderIncompatibleException:从数据库获取提供程序信息时发生错误。这可能是由实体框架使用不正确的连接字符串引起的。检查内部异常以获取详细信息,并确保连接字符串正确。
这是内部异常(具有特定细节):
System.Data.Entity.Core.ProviderIncompatibleException: The provider did not return a ProviderManifestToken string. ---> System.Data.SqlClient.SqlException: Login failed for user '[redacted]'.
at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)
at System.Data.SqlClient.SqlInternalConnectionTds.CompleteLogin(Boolean enlistOK)
at System.Data.SqlClient.SqlInternalConnectionTds.AttemptOneLogin(ServerInfo serverInfo, String newPassword, SecureString newSecurePassword, Boolean ignoreSniOpenTimeout, TimeoutTimer timeout, Boolean withFailover)
at System.Data.SqlClient.SqlInternalConnectionTds.LoginNoFailover(ServerInfo serverInfo, String newPassword, SecureString newSecurePassword, Boolean redirectedUserInstance, SqlConnectionString connectionOptions, SqlCredential credential, TimeoutTimer timeout)
at System.Data.SqlClient.SqlInternalConnectionTds.OpenLoginEnlist(TimeoutTimer timeout, SqlConnectionString connectionOptions, SqlCredential credential, String newPassword, SecureString newSecurePassword, Boolean redirectedUserInstance)
at System.Data.SqlClient.SqlInternalConnectionTds..ctor(DbConnectionPoolIdentity identity, SqlConnectionString connectionOptions, SqlCredential credential, Object providerInfo, String newPassword, SecureString newSecurePassword, Boolean redirectedUserInstance, SqlConnectionString userConnectionOptions, SessionData reconnectSessionData)
at System.Data.SqlClient.SqlConnectionFactory.CreateConnection(DbConnectionOptions options, DbConnectionPoolKey poolKey, Object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningConnection, DbConnectionOptions userOptions)
at System.Data.ProviderBase.DbConnectionFactory.CreatePooledConnection(DbConnectionPool pool, DbConnection owningObject, DbConnectionOptions options, DbConnectionPoolKey poolKey, DbConnectionOptions userOptions)
at System.Data.ProviderBase.DbConnectionPool.CreateObject(DbConnection owningObject, DbConnectionOptions userOptions, DbConnectionInternal oldConnection)
at System.Data.ProviderBase.DbConnectionPool.UserCreateRequest(DbConnection owningObject, DbConnectionOptions userOptions, DbConnectionInternal oldConnection)
at System.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, UInt32 waitForMultipleObjectsTimeout, Boolean allowCreate, Boolean onlyOneCheckConnection, DbConnectionOptions userOptions, DbConnectionInternal& connection)
at System.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal& connection)
at System.Data.ProviderBase.DbConnectionFactory.TryGetConnection(DbConnection owningConnection, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal oldConnection, DbConnectionInternal& connection)
at System.Data.ProviderBase.DbConnectionInternal.TryOpenConnectionInternal(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions)
at System.Data.SqlClient.SqlConnection.TryOpenInner(TaskCompletionSource`1 retry)
at System.Data.SqlClient.SqlConnection.TryOpen(TaskCompletionSource`1 retry)
at System.Data.SqlClient.SqlConnection.Open()
at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.<>c__DisplayClass1.<Execute>b__0()
at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute[TResult](Func`1 operation)
at System.Data.Entity.SqlServer.SqlProviderServices.UsingConnection(DbConnection sqlConnection, Action`1 act)
at System.Data.Entity.SqlServer.SqlProviderServices.UsingMasterConnection(DbConnection sqlConnection, Action`1 act)
at System.Data.Entity.SqlServer.SqlProviderServices.GetDbProviderManifestToken(DbConnection connection)
at System.Data.Entity.Core.Common.DbProviderServices.GetProviderManifestToken(DbConnection connection)
--- End of inner exception stack trace ---
at System.Data.Entity.Core.Common.DbProviderServices.GetProviderManifestToken(DbConnection connection)
at System.Data.Entity.Utilities.DbProviderServicesExtensions.GetProviderManifestTokenChecked(DbProviderServices providerServices, DbConnection connection)
问题本身非常明确:用户无权访问。但是,不是清楚的是,我们正在尝试打开哪个数据库。当我在一个调用的范围内使用多个数据库(几个DbContexts)时,我想知道哪个数据库拒绝我的用户,我想快速,轻松地知道它。
因此,我正在寻找一些方法来覆盖连接的开放,这样我就可以捕获异常并用更多信息包装它。但是,我没有看到一种简单的方法,因为DbContext
只使用DbConnection
。如何挂钩此过程以包装连接开口?或者有更好的方法来获取这些信息而不是我正在尝试做的事情吗?
异常本身并没有给我一个有用的堆栈跟踪,因为我的服务完全是async
。
答案 0 :(得分:2)
内部异常包含您可能需要的大部分细节。在这种情况下,基本异常是SqlException
try
{
//code that fires the error
}
catch (ProviderIncompatibleException ex)
{
SqlException baseException = ex.GetBaseException() as SqlException;
Console.WriteLine(baseException.Server);
}
您可以在捕获异常的任何地方记录此附加信息。
答案 1 :(得分:0)
public class MyContext : DbContext
{
public MyContext() : base(new MyDbConnection(), true) {
}
}
public class MyDbConnection : DbConnection
{
private SqlConnection connection;
public MyDbConnection() {
// init connection here
}
protected override DbTransaction BeginDbTransaction(IsolationLevel isolationLevel) {
return connection.BeginTransaction();
}
public override void Close() {
connection.Close();
}
public override void ChangeDatabase(string databaseName) {
connection.ChangeDatabase(databaseName);
}
public override void Open() {
try {
connection.Open();
}
catch (Exception ex) {
throw new MyCustomException(this.ConnectionString, ex);
}
}
public override string ConnectionString {
get {
return this.connection.ConnectionString;
}
set {
this.connection.ConnectionString = value;
}
}
public override string Database {
get {
return this.connection.Database;
}
}
public override ConnectionState State {
get {
return this.connection.State;
}
}
public override string DataSource {
get {
return this.connection.DataSource;
}
}
public override string ServerVersion {
get {
return this.connection.ServerVersion;
}
}
protected override DbCommand CreateDbCommand() {
return this.connection.CreateCommand();
}
}
你明白了:)祝你好运