背景:去年曾经开发过一款基于单机版的进销存系统,是基于sqlexpress 2005 数据库。考虑到时单机版,所以在打包的时候将sqlexpress 也直接打到压缩包中了,这样比较方便,完全自动安装,包括初始化数据库,初始化数据都是些在代码当中,客户在安装的时候只需要点下一步即可。
新需求:要求曾经的单机版程序需要在局域网内访问。
解决办法:系统分为两个版本,服务版安装数据库,客户版不安装数据库。将服务版sqlexpress数据库开启远程服务,然后客户版连接服务版上的数据库。
新问题:用户计算机水平非常低,又不能全部上门服务,要求所有操作通过代码自动实现。
1. 设置sqlexpress数据库允许通过账号混合模式验证登陆(默认是windows身份验证)
以下为实现代码:
RegistryKey hklm = Registry.LocalMachine; RegistryKey MSSQLServer = hklm.OpenSubKey("SOFTWARE", true) .OpenSubKey("Microsoft", true) .OpenSubKey("Microsoft SQL Server", true) .OpenSubKey("MSSQL.1", true) .OpenSubKey("MSSQLServer", true); MSSQLServer.SetValue("LoginMode", 2);
2. 设置sqlexpress数据库允许远程连接访问(开启TCP/IP访问协议)
以下为实现代码:
RegistryKey Tcp = MSSQLServer.OpenSubKey("SuperSocketNetLib", true) .OpenSubKey("Tcp", true); Tcp.SetValue("Enabled", 1);
3. 使系统sa账号可用,并设置sa的密码为sa2005(默认sa状态为不可用)
以下为实现代码:
string strConn = @"Data Source=(local)\SQLEXPRESS;Initial Catalog=master;"; strConn += "trusted_connection=sspi;Connect Timeout=30"; SqlConnection conn = null; try { conn = new SqlConnection(strConn); conn.Open(); SqlCommand command = new SqlCommand("Alter LOGIN sa ENABLE ; Alter LOGIN sa WITH PASSWORD = 'sa2005' ; ", conn); command.ExecuteNonQuery(); } catch (Exception ex) { } finally { if (conn != null) { conn.Close(); } }
4. 重新启动服务,并将服务设置为Automatic。
以下为实现代码:
ServiceControllerEx scEx = new ServiceControllerEx("SQL Server Browser"); scEx.StartupType = "Automatic"; if (scEx.Status != ServiceControllerStatus.Running) { scEx.Start(); } ServiceControllerEx SQLServer = new ServiceControllerEx("SQL Server (SQLEXPRESS)"); if (SQLServer.Status == ServiceControllerStatus.Running) { SQLServer.Stop(); while (SQLServer.Status != ServiceControllerStatus.Stopped) { Thread.Sleep(200); SQLServer.Refresh(); } SQLServer.Start(); while (SQLServer.Status != ServiceControllerStatus.Running) { Thread.Sleep(200); SQLServer.Refresh(); } } else { SQLServer.Start(); } }
5. ServiceControllerEx 类,对系统ServiceController的扩展。
class ServiceControllerEx : ServiceController { public ServiceControllerEx() : base() { } public ServiceControllerEx(string name) : base(name) { } public ServiceControllerEx(string name, string machineName) : base(name, machineName) { } public string StartupType { get { if (this.ServiceName != null) { //construct the management path string path = "Win32_Service.Name='" + this.ServiceName + "'"; ManagementPath p = new ManagementPath(path); //construct the management object ManagementObject ManagementObj = new ManagementObject(p); return ManagementObj["StartMode"].ToString(); } else { return null; } } set { if (value != "Automatic" && value != "Manual" && value != "Disabled") throw new Exception("The valid values are Automatic, Manual or Disabled"); if (this.ServiceName != null) { //construct the management path string path = "Win32_Service.Name='" + this.ServiceName + "'"; ManagementPath p = new ManagementPath(path); //construct the management object ManagementObject ManagementObj = new ManagementObject(p); //we will use the invokeMethod method of the ManagementObject class object[] parameters = new object[1]; parameters[0] = value; ManagementObj.InvokeMethod("ChangeStartMode", parameters); } } } }
6. 客户端方法(为了那些计算机名都不会看的客户),检测可连接的数据库。
需要引入COM组件 Microsoft SQLDMO Object Library,无需注册。
SQLDMO.ApplicationClass sqlApp = new SQLDMO.ApplicationClass(); SQLDMO.NameList nameList; int i = 0; nameList = sqlApp.ListAvailableSQLServers(); for (i = 1; i < nameList.Count; i++) { MessageBox.Show(nameList.Item(i).ToString()); }
通过这6步,达到完全代码开启sqlexpress远程服务。
如果sqlexpress数据库安装在win7 系统下,需要关闭防火墙,或者为1434端口和sqlserver.exe设置例外。