Ответ 1
Попробуйте добавить это в свой Web.Config.
<identity impersonate="true"/>
Здесь мой стек безопасности Windows/.NET:
В моей стандартной среде VS2008 DEV у меня есть этот один метод, который вызывается из приложения ASP.NET, который отлично работает:
private static void StopStartReminderService() {
ServiceController svcController = new ServiceController("eTimeSheetReminderService");
if (svcController != null) {
try {
svcController.Stop();
svcController.WaitForStatus(ServiceControllerStatus.Stopped, TimeSpan.FromSeconds(10));
svcController.Start();
} catch (Exception ex) {
General.ErrorHandling.LogError(ex);
}
}
}
Когда я запускаю это на производственном сервере, я получаю следующую ошибку от ServiceController:
Источник: System.ServiceProcess → System.ServiceProcess.ServiceController → IntPtr GetServiceHandle (Int32) → System.InvalidOperationException Сообщение: Не удается открыть службу eTimeSheetReminderService на компьютере. '.
Почему это происходит и как его исправить?
EDIT:
Ответ ниже, в основном в комментариях, но для уточнения:
статья MS KB и это, просто чтобы получить лучшее понимание
ПРИМЕЧАНИЕ: Я не выдаю себя за помощью через web.config, я делаю это в коде. См. Статью MS KB выше.
Попробуйте добавить это в свой Web.Config.
<identity impersonate="true"/>
Чтобы предоставить разрешение IIS для запуска/остановки определенной службы:
subinacl /service {yourServiceName} /grant=IIS_WPG=F
Это предоставляет права управления полным сервисом для этой конкретной службы во встроенную группу IIS_WPG. (Это работает для IIS6/Win2k3.) YMMV для новых версий IIS.)
Это был хороший вопрос, который тоже заинтриговал меня...
Итак, вот что я сделал для решения этой проблемы:
Шаг 3: Используйте олицетворение для олицетворения использования, созданного на шаге 1, для запуска и остановки службы
public const int LOGON32_PROVIDER_DEFAULT = 0;
WindowsImpersonationContext _impersonationContext;
[DllImport("advapi32.dll")]
// ReSharper disable once MemberCanBePrivate.Global
public static extern int LogonUserA(String lpszUserName,
String lpszDomain,
String lpszPassword,
int dwLogonType,
int dwLogonProvider,
ref IntPtr phToken);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
// ReSharper disable once MemberCanBePrivate.Global
public static extern int DuplicateToken(IntPtr hToken,
int impersonationLevel,
ref IntPtr hNewToken);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
// ReSharper disable once MemberCanBePrivate.Global
public static extern bool RevertToSelf();
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
// ReSharper disable once MemberCanBePrivate.Global
public static extern bool CloseHandle(IntPtr handle);
private bool _impersonate;
public bool ImpersonateValidUser(String userName, String domain, String password)
{
IntPtr token = IntPtr.Zero;
IntPtr tokenDuplicate = IntPtr.Zero;
if (RevertToSelf())
{
if (LogonUserA(userName, domain, password, LOGON32_LOGON_INTERACTIVE,
LOGON32_PROVIDER_DEFAULT, ref token) != 0)
{
if (DuplicateToken(token, 2, ref tokenDuplicate) != 0)
{
var tempWindowsIdentity = new WindowsIdentity(tokenDuplicate);
_impersonationContext = tempWindowsIdentity.Impersonate();
if (_impersonationContext != null)
{
CloseHandle(token);
CloseHandle(tokenDuplicate);
_impersonate = true;
return true;
}
}
}
}
if (token != IntPtr.Zero)
CloseHandle(token);
if (tokenDuplicate != IntPtr.Zero)
CloseHandle(tokenDuplicate);
_impersonate = false;
return false;
}
#region Implementation of IDisposable
#endregion
#region Implementation of IDisposable
private void Dispose(bool dispose)
{
if (dispose)
{
if (_impersonate)
_impersonationContext.Undo();
_impersonationContext.Dispose();
}
}
public void Dispose()
{
Dispose(true);
}
#endregion
public static void StartStopService(bool startService, string serviceName)
{
using (var impersonateClass = new Impersonation())
{
impersonateClass.ImpersonateValidUser(Settings.Default.LocalUsername, Settings.Default.Domain, Settings.Default.Password);
using (var sc = new ServiceController(serviceName))
{
if (startService)
sc.Start();
else if (sc.CanStop)
sc.Stop();
}
}
}
Обновление для IIS 8 (и, возможно, несколько более ранних версий)
Сгруппировка IIS_WPG больше не существует. Он изменился на IIS_IUSRS.
Кроме того, чтобы начать остановку службы, необязательно давать полные разрешения (F). Разрешений на запуск, остановку и приостановку обслуживания (TOP) должно быть достаточно. Таким образом, команда должна быть:
subinacl/service {yourServiceName}/grant = IIS_IUSRS = TOP
Обратите внимание, что перед запуском этой команды вам нужно указать командную строку (предпочтительно повышенную для запуска от имени администратора) до C:\Windows\System32
Folder.
Также убедитесь, что вы скопировали файл subinacl.exe в C:\Windows\System32
из каталога установки, если есть ошибка.
Просто догадка, но мне не кажется, что ошибка обязательно связана с безопасностью. Вы предоставляли услугу с тем же именем на производственном сервере?
Если ваше веб-приложение имеет доступ к базе данных и службе Windows, вы можете просто использовать флаг в БД для перезапуска службы. В службе вы можете прочитать этот флаг и перезапустить, если не заняты и т.д. Только в том случае, если вы можете изменить код службы. Если это сторонний сервис, вы можете создать свою собственную службу Windows и использовать конфигурацию базы данных для управления (перезапуска) служб. Это безопасный способ и дает вам гораздо большую гибкость и безопасность.