Contexte
Nous avons une application web asp.net 4.0 écrite en C# qui appelle un service web .net 3.5 écrit en C#. Le service web reçoit un identifiant d'utilisateur et renvoie une liste de données en fonction des groupes Active Directory auxquels l'utilisateur appartient.
Le service web utilise la version .net 3.5 de System.DirectoryServices.AccountManagement pour obtenir les Sids des groupes auxquels l'utilisateur appartient.
L'appel à UserPrincipal.GetGroups échoue par intermittence avec l'erreur ci-dessous. Il y a eu de très longues périodes de temps entre les occurrences, mais lorsqu'elles se sont produites, elles ont été répétées pendant plusieurs minutes. Le problème s'est produit pour différents utilisateurs AD.
La trace de la pile de cette exception n'avait aucun sens pour nous. Nous avons passé beaucoup de temps à examiner le code de Microsoft AD dans Reflector/ILSpy, mais nous n'avons pas pu aller au-delà de l'appel à 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)
Code à reproduire
Veuillez noter que la méthode CauseNotSupportedException imite le code qui ne s'exécute pas dans notre application mais dans un code situé ailleurs dans l'environnement que nous ne contrôlons pas.
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);
}
}
}
Implémentation de Stream pour imiter le comportement de 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) { }
}
Questions
- Si vous exécutez l'exemple ci-dessus, l'erreur qui se produit dans la méthode CauseNotSupportedException est déclenchée dans l'appel à GetGroups. Comment cela se fait-il ? Nous vous remercions de nous faire part de toute théorie ou de tout commentaire supplémentaire.
- Avez-vous des suggestions sur la façon d'approfondir la question ?
- Avez-vous d'autres suggestions que d'attraper l'exception et de réessayer ? C'est notre méthode de travail actuelle.
Gracias.
Clarification
Je ne suis pas sûr d'avoir été très clair dans mes explications, alors voici quelques précisions. Tout d'abord, je suis satisfait du code de l'annuaire actif qui obtient les Sids. Il fait ce que je veux qu'il fasse et je ne pense pas que le problème soit là en tant que tel. Le vrai problème est que lorsqu'une erreur se produit dans un autre code non lié (ce n'est pas dans notre application), l'erreur se manifeste dans l'appel GetGroups, d'où l'étrange trace de pile avec l'erreur survenant à l'origine dans System.Web.HttpResponseStream.get_Position(). Dans l'exemple d'application, NotSupportedException se produit dans CauseNotSupportedException mais le code ne s'arrête pas là, il s'arrête lors de l'appel à GetGroups. Si vous commentez CauseNotSupportedException() dans l'application exemple, l'erreur ne se produit jamais.
Je ne vois pas très bien comment cela peut se produire.