Странная периодически возникающая ошибка обработки ошибок при вызове UserPrinciapl.GetGroups в System.DirectoryServices.AccountManagement

Предпосылки

У нас есть веб-приложение asp.net 4.0, написанное на C #, которое вызывает веб-службу .net 3.5, написанную на C # . Веб-сервису передается идентификатор пользователя, и он возвращает список данных в зависимости от активных групп каталогов, к которым принадлежит пользователь.

Веб-служба использует версию .net 3.5 System.DirectoryServices.AccountManagement для получения идентификаторов SID групп, к которым принадлежит пользователь.

Вызов UserPrincipal.GetGroups периодически завершается сбоем из-за ошибки, указанной ниже. Между событиями были очень большие промежутки времени, но когда они действительно происходили, они повторялись неоднократно в течение нескольких минут. Проблема возникла для разных пользователей AD.

Трассировка стека этого исключения не имела для нас никакого смысла. Мы потратили много времени на изучение кода Microsoft AD в Reflector / ILSpy, но не смогли выйти за рамки вызова IADsPathName.Retrieve.

Exception

System.NotSupportedException: Specified method is not supported.
at System.Web.HttpResponseStream.get_Position()
at System.Drawing.UnsafeNativeMethods.ComStreamFromDataStream.Seek(Int64 offset, Int32 origin)
at System.DirectoryServices.AccountManagement.UnsafeNativeMethods.IADsPathname.Retrieve(Int32 lnFormatType)
at System.DirectoryServices.AccountManagement.ADStoreCtx.LoadDomainInfo()
at System.DirectoryServices.AccountManagement.ADStoreCtx.get_DnsForestName()
at System.DirectoryServices.AccountManagement.ADStoreCtx.GetGroupsMemberOf(Principal p)
at System.DirectoryServices.AccountManagement.Principal.GetGroupsHelper()
at System.DirectoryServices.AccountManagement.Principal.GetGroups()
at Data.SoftwarePublishingItemData.GetSids(String requestedForUserId)
at Data.SoftwarePublishingItemData.GetSoftwarePublishingItems(IDatabaseContext dbContext, GetSoftwarePublishingItemsSettings settings, XBXmlDocument parameters)
at Web.GetSoftwarePublishingItems.GetFlexiFieldData(String xml)

Код для воспроизведения

Обратите внимание, что метод CauseNotSupportedException имитирует код, который не выполняется в нашем приложении, а находится в другом месте в среде, которую мы не контролируем.

class Program
{
    static void Main(string[] args)
    {
        CauseNotSupportedException();

        string samAccountName = "domain.user";

        using (var principalContext = new PrincipalContext(ContextType.Domain))
        {
            using (var userPrincipal = UserPrincipal.FindByIdentity(principalContext, IdentityType.SamAccountName, samAccountName))
            {
                if (userPrincipal == null)
                    throw new ActiveDirectoryObjectNotFoundException();

                using (var groups = userPrincipal.GetGroups())
                {
                    foreach (GroupPrincipal group in groups)
                    {
                        Console.WriteLine(group.Sid);
                    }
                }
            }
        }
    }

    public static void CauseNotSupportedException()
    {
        using (var b = new Bitmap(500, 500, PixelFormat.Format32bppArgb))
        {
            b.Save(new FakeStream(), ImageFormat.Png);
        }
    }
}

Реализация Stream для имитации поведения HttpResponseStream

public class FakeStream : Stream
{
    public override bool CanRead { get { return false; } }
    public override bool CanSeek { get { return false; } }
    public override bool CanWrite { get { return true; } }

    public override void Flush() { }

    public override long Length { get { throw new NotSupportedException("No Seek"); } }

    public override long Position
    {
        get { throw new NotSupportedException("No Seek"); }
        set { throw new NotSupportedException("No Seek"); }
    }

    public override int Read(byte[] buffer, int offset, int count)
    {
        throw new InvalidOperationException("Write only stream");
    }

    public override long Seek(long offset, SeekOrigin origin)
    {
        throw new NotSupportedException("net_noseek");
    }

    public override void SetLength(long value) { }

    public override void Write(byte[] buffer, int offset, int count) { }
}

Вопросы

  1. Если вы запустите приведенный выше пример, ошибка, возникающая в методе CauseNotSupportedException, будет выдана при вызове GetGroups.Как это может быть? Приветствуются любые теории или дальнейшее понимание.
  2. Есть предложения, как продолжить расследование?
  3. Есть ли лучшие предложения, чем перехват исключения и повторная попытка? Это наша текущая работа.

Спасибо.

Разъяснение

Я не уверен, насколько ясно я был в своем объяснении, поэтому вот некоторые пояснения. Во-первых, я доволен кодом активной директории, который получает Sids. Это делает то, что я хочу, и я не думаю, что проблема в этом как таковая. Реальная проблема заключается в том, что когда ошибка возникает в другом несвязанном коде (его нет в нашем приложении), ошибка проявляется в вызове GetGroups, отсюда и странная трассировка стека с ошибкой, изначально возникшей в System.Web.HttpResponseStream.get_Position (). В примере приложения NotSupportedException возникает в CauseNotSupportedException, но код там не прерывается, он прерывается при вызове GetGroups. Если вы закомментируете CauseNotSupportedException () в примере приложения, ошибка никогда не возникнет.

Мне непонятно, как такое могло случиться.

6
задан Simon Vane 6 January 2012 в 10:12
поделиться