• 递归同步AD账号


    思路:因为AD本身就是一棵树,而且.Net Framework中提供了对AD的操作对象(DirectoryEntry).该对象包含children和parent属性.所以利用这些属性使用递归算法可以批量生成Insert语句.获得这些SQL语句后,你就可以按照你想要的方式来执行了.

    假设你的部门表有三个字段:DeptID,DeptName,ParentDeptID.根据一般情况,DeptID分类两种类型:整型和GUID类型.DeptName为字符型,ParentDeptID跟DeptID一致.

    先说DeptID为GUID类型:

    这种情况比较简单,因为window os 中的AD存储时,默认使用GUID作为唯一标识.而且DirectoryEntry对象正好包含GUID属性.这样我们就可以方便的遍历出AD中的所有项,而且因为使用递归算法,遍历完生成的SQL已经包含了层级关系.看代码:


    static StringBuilder sbDepts=new StringBuilder ();

    public static string GetBatchSQLFromSRC(DirectoryEntry entry) {

        DirectoryEntries entries 
    = entry.Children;
        
    foreach (DirectoryEntry item in entries){
            sbDepts.Append(
    string.Format("INSERT INTO Ts_Dept(DeptID,DeptName,ParentDeptID) VALUES <br /> ({0},'{1}','{2}') <br />", item.Guid, item.Name, entry.Guid));

                    GetBatchSQLFromSRC(item, intchildDeptID);   
    //递归调用

    }
        
    return sbDepts.ToString();
    }

    这个方法返回一个批量的SQL,可以使用事物来执行这个方法。

    再说DeptID为整型的情况:

    这种情况稍微复杂,因为递归方法本身的特点,一旦某个节点既有子节点又有兄弟节点(确切的说是弟节点),那么就会出现重复的DeptID。为了避免这种情况,需要额外的声明一个静态变量单独存储递归过程中的DeptID最大值。然后使用这个静态变量在递归过程中传递就可以避免重号。


    static StringBuilder sbDepts=new StringBuilder ();

    static int intchildDeptID = 10002;//可做成配置,具体值可以根据实际情况设定

    public static string GetBatchSQLFromSRC(DirectoryEntry entry,int pid) {

        DirectoryEntries entries 
    = entry.Children;
       intchildDeptID 
    = pid == intchildDeptID ? pid + 1 : intchildDeptID;//避免重号
        foreach (DirectoryEntry item in entries){
                 sbDepts.Append(
    string.Format("INSERT INTO Ts_Dept(DeptID,DeptName,ParentID) VALUES ({0},'{1}',{2}) <br />", intchildDeptID, item.Name, pid));
            GetBatchSQLFromSRC(item, intchildDeptID); 
    //递归调用
             }
        
    return sbDepts.ToString();
    }

    下面两个是辅助方法。第一个用来获取指定LDAP路径下的所有节点,另一个是在第一个方法中找特定的节点。

    /// <summary>
    /// 获取AD中指定目录下所有单位
    /// </summary>
    /// <param name="filter">DirectorySearcher的过滤条件</param>
    /// <returns></returns>
    public static SearchResultCollection GetADDepts(string filter) {
        DirectoryEntry entry 
    = new DirectoryEntry(ADDeptPath);
        
    if (entry != null) {
            DirectorySearcher sercher;
            
    try{
                sercher 
    = new DirectorySearcher(entry);
                sercher.Filter 
    = filter;
            }
            
    catch(Exception ex){
                
    throw ex;
            }
            
    return sercher.FindAll();
        }
        
    return null;
    }

    private static readonly string ADDeptPath = ConfigurationManager.AppSettings["ADDept"];//要获取的AD账号的域。

    Config中的配置格式格式:

    <add key="ADDept" value="LDAP://OU=Company,DC=caini,DC=ac,DC=cn"/><!--要同步的单位在AD中的路径-->

     

    /// <summary>
    /// 获取指定LDAP路径对应的AD对象
    /// </summary>
    /// <param name="path"></param>
    /// <returns></returns>
    public static DirectoryEntry GetDirectotyEntryInCollection(string path) {
        
    foreach (SearchResult result in GetADDepts()) {
            
    if (result.Path == path){             
                
    return result.GetDirectoryEntry();
            }
        }
        
    return null;
    }

    为了方便客户端代码调用,可以把递归方法封装一下。下面只封装了GUID类型的,整型的大家可以自己试着封装一下。如下:

    /// <summary>
    /// 从域中获取
    /// </summary>
    /// <param name="path"></param>
    /// <returns></returns>
    public static string GetBatchSQLFromSRC(string path) {
        sbDepts.Length 
    = 0;
        
    //SearchResult result = GetSearchResultInCollection(path);
        DirectoryEntry entry = GetDirectotyEntryInCollection(path);
        
    int rootdeptid = 10001;
        
    //return GetBatchSQLFromSRC(entry);
        return GetBatchSQLFromSRC(entry, rootdeptid);
    }

    这样客户端代码只要传递一个合法的LDAP路径,就可以获取该路径下所有的节点。

    例如:

    protected void Page_Load(object sender, EventArgs e)
    {
        
    if (!this.IsPostBack) {
            
    string path = "LDAP://OU=NewDept1,OU=Company,DC=caini,DC=ac,DC=cn";
            
    string ret = ADHelper.GetBatchSQLFromSRC(path);
            Response.Clear();
            Response.Write(ret);
            Response.End();
        }
    }

    注意:以上代码要引入

    1.using System.DirectoryServices;命名空间
    2.注意红体部门,为了灵活在web.config中做了配置

    以上代码要引入

    至于性能这块暂时还没考虑,如果大家有什么更好的办法请不吝赐教。

  • 相关阅读:
    C 应用
    C 基本语法
    iOS
    iOS
    iOS
    iOS
    iOS
    iOS
    iOS
    iOS
  • 原文地址:https://www.cnblogs.com/jjhe369/p/2042032.html
Copyright © 2020-2023  润新知