Используя localdb в SQL в службе Windows
у меня есть очень маленькое тестовое приложение, в котором я пытаюсь установить службу Windows и создать базу данных LocalDB во время процесса установки, а затем подключиться к этой базе данных LocalDB при запуске службы Windows.
я сталкиваюсь с огромными проблемами при подключении к экземпляру LocalDB из моей службы Windows.
мой процесс установки точно такой:
выполнить установки .msi-файл, который запускает процесс msiexec как NT AUTHORITYсистемная учетная запись.
-
запустите пользовательское действие для выполнения SqlLocalDB.exe со следующими командами:
- sqllocaldb.exe создать MYINSTANCE
- sqllocaldb.exe поделиться MYINSTANCE MYINSTANCESHARE
- sqllocaldb.exe запустить MYINSTANCE
-
запустите пользовательское действие C#, используя ADO.NET (система.Данные.SqlConnection) для выполнения следующих действий:
- подключиться к следующая строка подключения,
Data Source=(localdb)MYINSTANCE; Integrated Security=true
- создать базу данных TestDB
- использовать TestDB
- СОЗДАТЬ ТАБЛИЦУ ...
- подключиться к следующая строка подключения,
запустите службу Windows до завершения установки.
служба Windows устанавливается в учетную запись LocalSystem и также запускается как учетная запись пользователя NT AUTHORITYSYSTEM.
служба пытается подключиться, используя ту же строку подключения выше.
Я постоянно получаю следующую ошибку при попытке открыть соединение с вышеуказанной строкой соединения из службы Windows:
5 ответов
недавно я смог решить аналогичную проблему в нашем установщике WiX. У нас есть служба Windows, работающая под системной учетной записью, и установщик, где LocalDB-хранилище является одним из вариантов конфигурации базы данных. В течение некоторого времени (на самом деле пару лет) обновления и обслуживание продукта работали довольно хорошо, без проблем, связанных с LocalDB. Мы используем V11 по умолчанию.0 экземпляр, созданный в системном профиле в C:\Windows\System32\config дерево и база данных, указанная через AttachDbFileName, созданный в дереве ALLUSERSPROFILE. Поставщик БД настроен на использование проверки подлинности Windows. У нас также есть пользовательское действие в installer, запланированное как отложенное / не олицетворение, которое запускает обновления схемы БД.
все это работало нормально до недавнего времени. После еще одной связки обновлений БД наш новый выпуск начал терпеть неудачу после обновления по сравнению с прежним-служба не смогла начать, сообщая о печально известной " сетевой или конкретной ошибке, связанной с экземпляром установка соединения с SQL Server " (ошибка 50) ошибка.
при исследовании этой проблемы стало очевидно, что проблема заключается в том, что WiX выполняет пользовательские действия. Хотя не олицетворенные CA-s работают под системной учетной записью, профиль реестра и среда остаются текущим пользователем (я подозреваю, что WiX загружает их добровольно при подключении к сеансу пользователя). Это приводит к неправильному расширению пути из переменной LOCALAPPDATA-служба получает системный профиль один, но ЦС обновления схемы работает с ЦС пользователя.
так вот два возможных решения. Первый прост, но слишком навязчив для системы пользователя - с cmd.exe запускается через psexec, воссоздает сломанный экземпляр под системной учетной записью. Это не вариант для нас, так как пользователь может иметь другие базы данных, созданные в версии 11.0 экземпляр, который является публичным. Второй вариант предполагал много рефакторинга, но ничего не болит. Вот что нужно сделать, чтобы правильно запустить обновления схемы DB с LocalDB в WiX CA:
- настройте свой ЦС как отложенный / не олицетворяющий (должен работать под системной учетной записью);
-
исправить среду, чтобы указать пути системного профиля:
var systemRoot = Environment.GetEnvironmentVariable("SystemRoot"); Environment.SetEnvironmentVariable("USERPROFILE", String.Format(@"{0}\System32\config\systemprofile", systemRoot)); Environment.SetEnvironmentVariable("APPDATA", String.Format(@"{0}\System32\config\systemprofile\AppData\Roaming", systemRoot)); Environment.SetEnvironmentVariable("LOCALAPPDATA", String.Format(@"{0}\System32\config\systemprofile\AppData\Local", systemRoot)); Environment.SetEnvironmentVariable("HOMEPATH", String.Empty); Environment.SetEnvironmentVariable("USERNAME", Environment.UserName);
-
загрузить профиль учетной записи системы. Я использовал
LogonUser
/LoadUserProfile
собственные методы API, как показано ниже:[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool LogonUser( string lpszUserName, string lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken); [StructLayout(LayoutKind.Sequential)] struct PROFILEINFO { public int dwSize; public int dwFlags; [MarshalAs(UnmanagedType.LPWStr)] public String lpUserName; [MarshalAs(UnmanagedType.LPWStr)] public String lpProfilePath; [MarshalAs(UnmanagedType.LPWStr)] public String lpDefaultPath; [MarshalAs(UnmanagedType.LPWStr)] public String lpServerName; [MarshalAs(UnmanagedType.LPWStr)] public String lpPolicyPath; public IntPtr hProfile; } [DllImport("userenv.dll", SetLastError = true, CharSet = CharSet.Unicode)] [return: MarshalAs(UnmanagedType.Bool)] static extern bool LoadUserProfile(IntPtr hToken, ref PROFILEINFO lpProfileInfo); var hToken = IntPtr.Zero; var hProfile = IntPtr.Zero; bool result = LogonUser("SYSTEM", "NT AUTHORITY", String.Empty, 3 /* LOGON32_LOGON_SERVICE */, 0 /* LOGON32_PROVIDER_DEFAULT */, ref token); if (result) { var profileInfo = new PROFILEINFO(); profileInfo.dwSize = Marshal.SizeOf(profileInfo); profileInfo.lpUserName = @"NT AUTHORITY\SYSTEM"; if (LoadUserProfile(token, ref profileInfo)) hProfile = profileInfo.hProfile; }
оберните это в
IDisposable
классе и использоватьusing
оператор для построения контекста. самое главное - рефакторинг кода для выполнения необходимых обновлений БД в дочернем процессе. Это может быть простая exe-оболочка над DLL установщика или автономная утилита, если у вас уже есть один.
P.S. всех этих трудностей можно было бы избежать, если бы только Microsoft разрешила использовать выбор места для создания экземпляров LocalDB с помощью опции командной строки. Как, например, утилиты initdb/pg_ctl Postgres.
подбирая из комментариев по вопросу, вот некоторые области, чтобы посмотреть. Некоторые из них уже ответили в этих комментариях, но я документирую здесь для других, если информация может быть полезной.
-
проверьте здесь отличный источник информации о SQL Server Express LocalDB:
- среда SQL Server 2014 г. Экспресс localdb с
- поддержка SqlClient для Localdb с
- Sqllocaldb Utlity
-
представляем LocalDB, улучшенный SQL Express (также посмотрите раздел Q&A в конце основного сообщения, непосредственно перед комментариями, поскольку кто-то спросил, Можно ли запустить LocalDB из службы, и ответ:
LocalDB может быть запущен из службы, если профиль загружен для службы счет.
-
какая версия .Net используется? Здесь это 4.5.1 (хорошо), но более ранние версии не могли обрабатывать предпочтительную строку соединения (т. е.
@"(localdb)\InstanceName"
). Следующая цитата взята из ссылки, указанной выше:если приложение использует версию .NET до версии 4.0.2, необходимо подключиться непосредственно к именованному каналу На localdb.
и согласно странице MSDN для объект sqlconnection.Параметр connectionString:
начиная с .NET Framework 4.5, вы также можете подключиться к базе данных LocalDB следующим образом:
server=(localdb)\myInstance
-
пути:
случаях: C:\Users{вход в систему Windows}\AppData\Local\Microsoft\Microsoft SQL Server локальный DB\Instances
-
базы данных:
- создано через SSMS или прямое соединение:C:\Users{Вход В Систему Windows}\Documents или C:\Users{Вход В Систему Windows}
- создано с помощью Visual Studio:C:\Users{вход в систему Windows}\AppData\Local\Microsoft\VisualStudio\SSDT
-
начальный Проблема
- симптомы:
- файлы базы данных (
.mdf
и.ldf
) создано в ожидаемом месте:
C:\Windows\System32\config\systemprofile - файлы экземпляров, созданные в неожиданном месте:
C:\Users\{текущий пользователь}\AppData\Local\Microsoft\Microsoft SQL Server локальная БД\экземпляры
- файлы базы данных (
- причина (Примечание взято из страницы MSDN" Sqllocaldb Utility", которая связана выше; акцент мой):
операции, отличные от start, могут выполняться только на экземпляре, принадлежащем в настоящее время зарегистрирован пользователь.
- симптомы:
-
вещи, чтобы попробовать:
- строка подключения, указывающая базу данных (хотя, возможно, длинный выстрел, если ошибка связана с невозможностью подключения к пример):
"Server=(LocalDB)\MYINSTANCE; Integrated Security=true ;AttachDbFileName=C:\Windows\System32\config\systemprofile\TestDB.mdf"
"Server=(LocalDB)\.\MYINSTANCESHARE; Integrated Security=true ;AttachDbFileName=C:\Windows\System32\config\systemprofile\TestDB.mdf"
служба запущена? Выполните следующие действия из командной строки:
TASKLIST /FI "IMAGENAME eq sqlservr.exe"
Вероятно, он должен быть указан в разделе "консоль" для столбца "имя сеанса"-
выполните следующие действия из командной строки:
sqllocaldb.exe info MYINSTANCE
И убедитесь, что значение "владелец" является правильным. Является ли значение "Shared name" тем, чем оно должно быть? Если нет, то документация гласит:только администратор на компьютере может создать общий экземпляр LocalDB
в рамках настройки добавьте
NT AUTHORITY\System
учетная запись в качестве входа в систему, которая требуется, если эта учетная запись не отображается как "владелец" экземпляра:CREATE LOGIN [NT AUTHORITY\System] FROM WINDOWS; ALTER SERVER ROLE [sysadmin] ADD MEMBER [NT AUTHORITY\System];
Проверьте следующий файл для подсказок / деталей:
C:\Users{Windows Логин}\папка AppData\местные\Майкрософт\корпорация Майкрософт SQL сервер локальной БД\инстансы\\МОЙЭКЗЕМПЛЯР ошибки.log-
в конце концов вам может потребоваться создать фактическую учетную запись для создания и владения экземпляром и базой данных, а также запустить службу. LocalDB действительно предназначен для пользовательского режима, и есть ли какой-либо недостаток в том, что ваш сервис имеет свой собственный логин? И вам, вероятно, не нужно будет делиться экземпляром в этот момент.
и на самом деле, как отметил Microsoft на SQL Server гггг Экспресс LocalDB страница MSDN:
экземпляр localdb с принадлежащий встроенным учетным записям, таким как NT AUTHORITY\SYSTEM, может иметь проблемы с управляемостью из-за перенаправления файловой системы windows; вместо этого используйте обычную учетную запись windows в качестве владельца.
обновление (2015-08-21)
на основе отзывов от O. P., что с помощью обычной учетной записи Пользователя может быть проблематичным в определенных средах и иметь в виду исходную проблему экземпляра LocalDB, создаваемого в %LOCALAPPDATA%
папка для пользователя, запускающего установщик (и не the на NT AUTHORITY\System), я нашел решение, которое, похоже, поддерживает цель простой установки (нет пользователя для создания) и не должно требовать дополнительного кода для загрузки системного профиля.
попробуйте использовать один из двух встроенных аккаунты то есть не the LocalSystem учетная запись (которая не поддерживает свою собственную информацию реестра. Использовать:
оба имеют свои папки профиля в: C:\Windows\ServiceProfiles
хотя я не смог протестировать через установщик, я тестировал вход в систему службы как НТ\орган записи networkservice установив экземпляр SQL Server Express 2014 для входа в систему под этой учетной записью и перезапустив службу SQL Server. Затем я пробежал следующее:
EXEC xp_cmdshell 'sqllocaldb c MyTestInstance -s';
и он создал экземпляр в:C:\Windows\ServiceProfiles\NetworkService\AppData\Local\Microsoft\Microsoft SQL Server локальные DB\экземпляры
затем я запустил следующее:
EXEC xp_cmdshell N'SQLCMD -S (localdb)\MyTestInstance -E -Q "CREATE DATABASE [MyTestDB];"';
и он создал базу данных в: C:\Windows\ServiceProfiles\NetworkService
Я предлагаю использовать другую учетную запись пользователя, а не системную учетную запись, выполнив следующие действия: -
- создайте новую учетную запись на машине и установите ее в качестве учетной записи под которым работает служба Windows. Это не лучшая практика, чтобы использовать системная учетная запись просто для запуска приложения, в любом случае, как разрешения являются чрезмерными.
- убедитесь, что разрешения на файлы LocalDB установлены, чтобы позволить указанной учетной записи пользователя получить доступ к базе данных (и, таким образом продолжать используйте интегрированную безопасность)
- убедитесь, что он работает, пытается подключиться к БД (после установки) под той же учетной записью пользователя, под управлением
sqlcmd
или студия управления в контексте указанного пользователя, затем подключение с помощью Integrated Безопасность для обеспечения его работы.
некоторые другие вещи, чтобы попробовать/подумать:
- вы проверили журнал событий Windows, для любых событий, которые могут быть полезны для диагностических целей?
- убедитесь, что если у вас есть какие-либо другие версии SQL Server (особенно до 2012 года), которые для средств командной строки, %PATH% не настроен на поиск более старой версии средств. Старые инструменты не поддерживают LocalDB.
- можно также (в качестве альтернативы) настроить LocalDB для совместного использования с другими пользователями. Это включает совместное использование экземпляра, а затем предоставление доступа другим пользователям. См. раздел "проблемы с общим доступом" в этой статье:Устранение неполадок SQL Server 2012 Express Localdb с.
там же еще одна так статья это может содержать более полезную информацию в ссылках внутри (измените язык в URL с польского на английский, изменив pl-pl на en-us). Его работа вокруг использует учетные записи SQL Server, которые могут быть не в порядке в вашем случае.
Это также может быть полезно, поскольку это относится к запрещенным разрешениям безопасности и возможным разрешениям: https://dba.stackexchange.com/questions/30383/cannot-start-sqllocaldb-instance-with-my-windows-account
Тревор, проблема у вас есть с пользовательскими действиями MSI. Вы должны настроить их с помощью "Impersonate=false", иначе пользовательские действия будут выполняться в контексте текущего пользователя.
кстати, какой инструмент вы используете для создания установщика? В зависимости от используемого инструмента, не могли бы вы предоставить скриншоты или фрагменты кода конфигурации пользовательских действий?
принятый ответ с этого поста даст вам дополнительную информацию о различные варианты выполнения настраиваемых действий: запустите ExeCommand в customAction в режиме администратора в установщике Wix
дополнительную информацию о олицетворении вы найдете здесь: http://blogs.msdn.com/b/rflaming/archive/2006/09/23/768248.aspx
Я бы не создавал базу данных под экземпляром localdb системы. Я бы создал его под текущим пользователем, устанавливающим продукт. Это сделает жизнь намного проще, если вам нужно удалить или управления базой данных. Они могут сделать это через SQL management studio. В противном случае вам придется использовать psexc или что-то еще для запуска процесса под системной учетной записью для управления им.
после создания БД используйте указанную Вами опцию share. Тогда система счета может доступ к базе данных через сетевое имя.
sqllocaldb поделиться MSSqlLocalDb LOCAL_DB
при совместном использовании я заметил, что вам придется перезапустить локальный экземпляр БД, чтобы фактически получить доступ к БД через имя общего ресурса:
sqllocaldb остановить MSSQLLocalDB
sqllocaldb запустить MSSQLLocalDB
кроме того, вам может потребоваться добавить системную учетную запись в качестве устройства чтения и записи БД в базу данных ...
exec для db_datareader для процедуры sp_addrolemember , 'NT AUTHORITY\SYSTEM'