На http://msdn.microsoft.com/en-us/library/w070t6ka(v=VS.100).aspx есть пример того, как выполнять олицетворение с .net 4.0. Мы использовали этот пример в классе, который наследует IDisposable для простоты использования. Однако, когда мы используем этот класс в веб-приложении asp.net, мы замечаем небольшое, но неуклонное увеличение числа байт в выгружаемом пуле монитора производительности. Через неделю приложение вылетает.
Я пробовал разные реализации класса олицетворения, используя http://msdn.microsoft.com/en-us/library/w070t6ka(v=VS.90).aspx и http://support.microsoft.com/kb/306158 в качестве ссылки, но все они показывают одинаковую утечку.
Откуда эта утечка? Есть ли проблема с Windows API? Мы работаем под управлением Windows 2008 R2.
Это наша текущая версия класса олицетворения:
public class Impersonator : IDisposable
{
public Impersonator(string username, string domain, string password)
{
if (!ImpersonateValidUser(username, domain, password))
{
throw new SecurityException("Could not impersonate. Wrong username / password");
}
}
public void Dispose()
{
UndoImpersonation();
}
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword, int dwLogonType, int dwLogonProvider, out SafeTokenHandle phToken);
private const int LOGON32_PROVIDER_DEFAULT = 0;
private const int LOGON32_LOGON_INTERACTIVE = 2; //This parameter causes LogonUser to create a primary token.
private WindowsImpersonationContext impersonatedUser;
private bool ImpersonateValidUser(string username, string domain, string password)
{
SafeTokenHandle safeTokenHandle;
// Call LogonUser to obtain a handle to an access token.
bool success = LogonUser(username, domain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, out safeTokenHandle);
if (success)
{
using (safeTokenHandle)
{
// Use the token handle returned by LogonUser.
WindowsIdentity newId = new WindowsIdentity(safeTokenHandle.DangerousGetHandle());
impersonatedUser = newId.Impersonate();
}
}
return success;
}
private void UndoImpersonation()
{
// Releasing the context object stops the impersonation
if (impersonatedUser != null)
{
impersonatedUser.Undo();
impersonatedUser.Dispose();
}
}
}
public sealed class SafeTokenHandle : SafeHandleZeroOrMinusOneIsInvalid
{
private SafeTokenHandle() : base(true)
{
}
[DllImport("kernel32.dll")]
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
[SuppressUnmanagedCodeSecurity]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool CloseHandle(IntPtr handle);
protected override bool ReleaseHandle()
{
return CloseHandle(handle);
}
}
А это график монитора производительности двух веб-серверов, использующих разные версии класса:
perfmon http://img222.imageshack.us/img222/5388/captureyog.png
Когда мы отключаем класс и используем глобальное олицетворение через web.config, эти строки полностью плоские.
Обновление
Я сделал тестовое приложение, которое успешно воспроизводит проблему. Его можно скачать здесь:
http://rapidshare.com/files/447325211/ImpersonationTest.zip
Результат за 18 часов выглядит так:
testapp http://img689.imageshack.us/img689/2055/impersonationtest.png