我正在使用桌面应用程序(C#,Windows Forms,MS SQL Server)。 其中一个应用程序要求是在PC启动时启动所以我放了一个 注册表中的值在以下键下
HKEY_LOCAL_MACHINE \ SOFTWARE \微软\的Windows \ CurrentVersion \ Run中
(我正在使用Windows 7家庭版的机器上工作)
当应用程序启动时,我在加载第一个表单之前检查sqlserver服务是否正在运行 我还检查了SQLBrowser服务并且它正在运行。
检查服务状态的代码
System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
ServiceController[] services = ServiceController.GetServices();
if (services.Where(s => s.ServiceName == ServiceName).FirstOrDefault() != null)
{
using (ServiceController sc = new ServiceController(ServiceName))
{
sw.Start();
while (sc.Status != ServiceControllerStatus.Running && sw.ElapsedMilliseconds < 300000)
{
sc.Refresh();
}
sw.Stop();
if (sc.Status != ServiceControllerStatus.Running)
{
return;
}
}
}
但是当我第一次与数据库建立连接时,会出现以下描述的异常
Cannot open database "xyz" requested by the login. The login failed.
Login failed for user 'ABCUser'.
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)
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, DbConnectionOptions options, DbConnectionPoolKey poolKey, DbConnectionOptions userOptions)
at System.Data.ProviderBase.DbConnectionPool.CreateObject(DbConnectionOptions userOptions)
at System.Data.ProviderBase.DbConnectionPool.UserCreateRequest(DbConnectionOptions userOptions)
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& connection)
at System.Data.ProviderBase.DbConnectionClosed.TryOpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions)
at System.Data.SqlClient.SqlConnection.TryOpen(TaskCompletionSource`1 retry)
at System.Data.SqlClient.SqlConnection.Open()
at CheckValidConnection(String ConnectionString)
我尝试连接windows用户,sa用户,为应用程序创建的具有数据库所有权限的其他用户 但结果是一样的
我认为这不是连接字符串问题或用户权限问题,因为如果我手动启动应用程序它工作正常并且作为最终解决方案我延迟了应用程序的启动30秒(在检查服务运行之后)它工作正常(但我不喜欢这个解决方案)
我很感激这个问题的任何帮助
更新 (感谢Nick.McDermaid指导我使用Errorlog) 我检查了sql server错误日志,找到了以下行
2018-02-22 14:10:49.19 Logon Error: 18456, Severity: 14, State: 38.
2018-02-22 14:10:49.19 Logon Login failed for user 'ABCUser'. Reason: Failed to open the explicitly specified database. [CLIENT: <local machine>]
2018-02-22 14:10:57.05 Logon Error: 18456, Severity: 14, State: 38.
2018-02-22 14:10:57.05 Logon Login failed for user 'NT AUTHORITY\NETWORK SERVICE'. Reason: Failed to open the explicitly specified database. [CLIENT:
<local machine>]
2018-02-22 14:10:57.27 Logon Error: 18456, Severity: 14, State: 38.
2018-02-22 14:10:57.27 Logon Login failed for user 'NT AUTHORITY\NETWORK SERVICE'. Reason: Failed to open the explicitly specified database. [CLIENT:
<local machine>]
2018-02-22 14:10:58.92 spid20s A new instance of the full-text filter daemon host process has been successfully started.
2018-02-22 14:10:58.95 spid17s Starting up database 'msdb'.
2018-02-22 14:10:58.95 spid16s Starting up database 'ReportServer'.
2018-02-22 14:10:58.95 spid18s Starting up database 'ReportServerTempDB'.
2018-02-22 14:10:58.95 spid19s Starting up database 'xyz'.
所以我认为问题是我在尝试接收请求之前尝试连接数据库(我不太清楚'启动数据库'是什么意思
'xyz'') 我试图通过2种方式在第一次与数据库交互之前检查数据库状态
1-使用SQL Server管理对象(SMO)
System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
var server = new Server(scsb.DataSource);
if (server.Databases.Contains(scsb.InitialCatalog))
{
Database db = server.Databases.Cast<Database>().FirstOrDefault(dbase => dbase.Name == scsb.InitialCatalog);
if (db == null) return false;
System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
sw.Start();
while (db.Status.HasFlag(DatabaseStatus.Normal) == false && sw.ElapsedMilliseconds <= 60000)
{
server.Refresh();
}
sw.Stop();
if (db.Status.HasFlag(DatabaseStatus.Normal) == true)
{
return true;
}
}
else
return false;
2-使用直接查询master db中的系统表
scsb.InitialCatalog = "master";
string CheckOnline = "";
System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
sw.Start();
using (SqlConnection scn = new SqlConnection(scsb.ConnectionString))
{
scn.Open();
while (CheckOnline != "ONLINE" && sw.ElapsedMilliseconds <= 60000)
{
CheckOnline = scn.Query<string>("SELECT state_desc FROM sys.databases WHERE name = @DBName ", new { DBName = OriginalDBName }).SingleOrDefault();
}
}
sw.Stop();
if (CheckOnline != "ONLINE")
{
return false;
}
现在的问题是两种技术都会在数据库实际联机之前返回数据库的在线状态 有没有其他方法来检查数据库是否实际在线