2012-01-04 15 views
6

nền

lỗi liên tục Chúng tôi có một asp.net ứng 4,0 web viết bằng C# mà các cuộc gọi một .net dịch vụ 3,5 web viết bằng C#. Các dịch vụ web được thông qua một id người dùng và trả về một danh sách các dữ liệu tùy thuộc vào các nhóm thư mục hoạt động người dùng thuộc về.Strange xử lý lỗi khi gọi UserPrinciapl.GetGroups trong System.DirectoryServices.AccountManagement

Dịch vụ web sử dụng phiên bản 3.5 của System.DirectoryServices.AccountManagement để nhận được Sids của các nhóm mà người dùng thuộc về.

Cuộc gọi đến UserPrincipal.GetGroups không liên tục với lỗi bên dưới. Đã có một khoảng thời gian rất dài giữa các lần xuất hiện nhưng khi nó xảy ra nó xảy ra liên tục trong vài phút. Sự cố đã xảy ra với những người dùng AD khác nhau.

Dấu vết ngăn xếp của ngoại lệ này không có ý nghĩa đối với chúng tôi. Chúng tôi đã dành rất nhiều thời gian nhìn vào mã AD của Microsoft trong Reflector/ILSpy nhưng không thể vượt quá cuộc gọi đến 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) 

Mã để tái tạo

Xin lưu ý, phương pháp CauseNotSupportedException được bắt chước mã mà không được chạy trong ứng dụng của chúng tôi nhưng trong mã ở một nơi khác trong môi trường mà chúng tôi không về kiểm soát.

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); 
     } 
    } 
} 

Thực hiện suối để bắt chước HttpResponseStream hành vi

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) { } 
} 

Câu hỏi

  1. Nếu bạn chạy các ví dụ trên các lỗi xảy ra trong phương pháp CauseNotSupportedException được ném vào hãy gọi tới GetGroups. Làm thế nào mà có thể được? Bất kỳ lý thuyết hoặc cái nhìn sâu sắc hơn sẽ được đánh giá cao.
  2. Bất kỳ đề xuất nào về cách điều tra thêm?
  3. Bất kỳ đề xuất nào tốt hơn là bắt ngoại lệ và thử lại? Đó là công việc hiện tại của chúng tôi.

Cảm ơn.

Làm rõ

Tôi không chắc chắn như thế nào rõ ràng tôi đã được trong lời giải thích của tôi vì vậy đây là một số giải thích. Thứ nhất, tôi hài lòng với mã thư mục hoạt động nhận được Sids. Điều đó làm những gì tôi muốn nó làm và tôi không nghĩ rằng vấn đề là với điều đó như vậy. Vấn đề thực sự là khi một lỗi xảy ra trong mã không liên quan khác (nó không có trong ứng dụng của chúng tôi), lỗi hiển thị trong cuộc gọi GetGroups, do đó theo dõi stack lạ với lỗi ban đầu xảy ra tại System.Web.HttpResponseStream.get_Position(). Trong ứng dụng mẫu NotSupportedException xuất hiện trong CauseNotSupportedException nhưng mã không bị phá vỡ ở đó, nó phá vỡ cuộc gọi đến GetGroups. Nếu bạn nhận xét ra CauseNotSupportedException() trong ứng dụng mẫu, lỗi sẽ không bao giờ xảy ra.

Tôi không rõ điều này có thể xảy ra như thế nào.

+0

Câu hỏi, bạn đang cố gắng tìm xem người dùng có thuộc một nhóm cụ thể hay không. Tôi đang cố gắng hiểu rõ hơn về những gì bạn đang thực sự tìm kiếm .. Tôi có thể có đề xuất về cách tiếp cận tốt hơn liên quan đến mã hóa .. đây là một liên kết sẽ giúp tôi cũng sẽ dán 2 đoạn mã dưới đây sẽ giúp bạn có được những gì bạn cần dễ dàng hơn. http://msdn.microsoft.com/en-us/magazine/cc135979.aspx – MethodMan

+0

Cảm ơn rất nhiều về phản hồi. Những gì tôi cần là danh sách các Sids của các nhóm mà người dùng là thành viên của. Tôi hiện đang sử dụng không gian tên System.DirectoryServices.AccountManagement (UserPrincipal.GetGroups nằm trong không gian tên đó). Vì vậy, mẫu mã của tôi rất giống với mẫu bạn đã đăng bên dưới. Mã tôi đã nhận được những gì tôi muốn tốt, nó chỉ là lỗi liên tục xảy ra gây ra bởi mã không liên quan mà tôi đang cố gắng để hiểu. Nếu bạn có thời gian nó sẽ là giá trị chạy mã mẫu và bước qua nó. –

+0

ok không phải là một vấn đề .. nó đã được khó khăn để xác định lúc đầu những gì bạn đang muốn .. lời xin lỗi của tôi bạn vẫn sẽ cần phải kiểm tra tài sản đó hoặc (string) Properties ["samAccountName"] [0]. ToString() vì điều này sẽ là một đối tượng tại thời điểm này .. hy vọng điều này có ý nghĩa .. – MethodMan

Trả lời

4

Sau khi thực hiện cuộc gọi hỗ trợ, Microsoft đã phát hành bản sửa lỗi nóng cho sự cố này. Xem liên kết bên dưới.

Nguyên nhân đã nêu là: "Sự cố này xảy ra do không gian tên System.DirectoryServices.AccountManagement là một trình bao bọc mỏng cho Giao diện dịch vụ Active Directory API (ADSI) gốc. Giao diện IErrorInfo được triển khai bởi giao diện IADsPathName phản hồi ngoại lệ mà ADSI không ném. Khi không có ngoại lệ ADSI trên ngăn xếp, giao diện IErrorInfo ném ngoại lệ ở trên cùng của ngăn xếp, ngay cả khi ngoại lệ được xử lý bởi một trình xử lý khác trong ứng dụng. "

http://support.microsoft.com/kb/2683913

Cảm ơn những người đã đề xuất.

0

Nếu bạn đang sử dụng .NET 3.5 trở lên, bạn có thể sử dụng không gian tên mới System.DirectoryServices.AccountManagement (S.DS.AM) giúp việc này trở nên dễ dàng hơn rất nhiều so với trước đây.

Đọc tất cả về nó ở đây: [Hiệu Trưởng Giám Directory Security trong .NET Framework 3.5] [1]

Về cơ bản, bạn cần phải có một "bối cảnh chính" (thường là tên miền của bạn), một hiệu trưởng người dùng, và sau đó bạn nhận được nhóm của mình rất dễ dàng:

public List<GroupPrincipal> GetGroups(string userName) 
{ 
    List<GroupPrincipal> result = new List<GroupPrincipal>(); 

    // establish domain context 
    PrincipalContext yourDomain = new PrincipalContext(ContextType.Domain); 

    // find your user 
    UserPrincipal user = UserPrincipal.FindByIdentity(yourDomain, username); 

    // if found - grab its groups 
    if(user != null) 
    { 
     PrincipalSearchResult<Principal> groups = user.GetAuthorizationGroups(); 

     // iterate over all groups 
     foreach(Principal p in groups) 
     { 
     // make sure to add only group principals or change this to add to a list or varible if needed. 
     if(p is GroupPrincipal) 
     { 
      result.Add(p); 
     } 
     } 
    } 

    return result; 
} 

để truy cập vào tính chất nhất định, không được nổi lên trên các đối tượng UserPrincipal, bạn cần phải thâm nhập vào các tiềm ẩn DirectoryEntry:

public string GetDepartment(Principal principal) 
{ 
    string result = string.Empty; 

    DirectoryEntry de = (principal.GetUnderlyingObject() as DirectoryEntry); 

    if (de != null) 
    { 
     if (de.Properties.Contains("samAccountName")) 
     { 
      result = de.Properties["samAccountName"][0].ToString(); 
     } 
    } 

    return result; 
} 

//Change this Method to fit what ever your needs desire.. 
public string GetDepartment(string username) 
{ 
    string result = string.Empty; 

    // if you do repeated domain access, you might want to do this *once* outside this method, 
    // and pass it in as a second parameter! 
    PrincipalContext yourDomain = new PrincipalContext(ContextType.Domain); 

    // find the user 
    UserPrincipal user = UserPrincipal.FindByIdentity(yourDomain, username); 

    // if user is found 
    if(user != null) 
    { 
     // get DirectoryEntry underlying it 
     DirectoryEntry de = (user.GetUnderlyingObject() as DirectoryEntry); 

     if (de != null) 
     { 
      if (de.Properties.Contains("department")) 
      { 
      result = de.Properties["department"][0].ToString(); 
      } 
     } 
    } 

    return result; 
}