Отображение Windows Active Directory thumbnailPhoto в приложении asp: net Search - PullRequest
0 голосов
/ 13 мая 2018

Я настроил веб-приложение для поиска в Active Directory нашей организации. Запрос (динамическое обёртывание SQL OpenQuery) возвращает также шестнадцатеричные данные для thumpnailPhoto.

Когда я показываю изображение, я получаю 40% успеха на всех отображаемых изображениях. «Плохие» обычно хороши в первых 15%, начиная сверху и заканчивая черными полосами. Иногда есть данные изображения, повторяющиеся в полосах ... Некоторые изображения профиля не отображаются вообще, а другие идеально. Должны быть разные форматы изображений, но без доступа к местам хранения этих изображений я больше не получаю.

Вот что я делаю: Я связываю данные из запроса с GridView.

protected void FillGrid(Object sender, EventArgs e)
{
    SqlConnection objConn = new SqlConnection("Data Source=XXXXXXXXXX");
    SqlDataAdapter adapter = new SqlDataAdapter();
    SqlCommand objCommand = new SqlCommand(@"declare @SQL nvarchar(4000)
                                             declare @Asterisc nvarchar(1)
                                             declare @Sub nvarchar(12)
                                             set @SearchName = CASE WHEN @SearchName = '' THEN '*' ELSE @SearchName END
                                             set @SearchSurename = CASE WHEN @SearchSurename = '' THEN '*' ELSE @SearchSurename END
                                             set @Asterisc = '*'
                                             set @Sub = CASE WHEN @Subsidiary = '*' THEN '' ELSE (@Subsidiary+', OU=') END
                                             set @SQL ='SELECT TOP (100) PERCENT samAccountName AS UserAccount, givenName AS FirstName, sn AS LastName, department, title AS Position, 
                                                               physicaldeliveryofficename AS Office, extensionAttribute1 AS PersonnelID, initials, mail AS email, telephonenumber AS Phone, extensionattribute5 AS Extension, 
                                                               mobile, extensionattribute3 AS MobileExt, thumbnailPhoto
                                                        FROM OPENQUERY(ADSI, ''SELECT samAccountName, givenName, sn, legacyExchangeDN, department, title, physicaldeliveryofficename, extensionAttribute1, distinguishedName, initials,
                                                                                      mail, telephonenumber, extensionattribute5, mobile, extensionattribute3, thumbnailPhoto
                                                                               FROM ''''LDAP://OU=' + @Sub + 'XXXX, DC=XXXX,DC=XXXX,DC=XXXX''''
                                                                               WHERE objectClass=''''Person'''' AND objectClass = ''''User'''' AND givenName = ''''' + @SearchName + ''''' AND samAccountName = ''''' + @SearchSurename + ''''' AND extensionAttribute1 = ''''' + @Asterisc + ''''' '') AS AD_Users
                                                        ORDER BY UserAccount'
                                                        exec (@SQL)", objConn);
    objCommand.Parameters.Add("@SearchName", SqlDbType.NVarChar).Value = TextBoxSearchName.Text;
    objCommand.Parameters.Add("@SearchSurename", SqlDbType.NVarChar).Value = TextBoxSearchSureName.Text;
    objCommand.Parameters.Add("@Subsidiary", SqlDbType.NVarChar).Value = DDSubsidiary.Text;
    DataTable t = new DataTable();
    adapter.SelectCommand = objCommand;
    objConn.Open();
    adapter.Fill(t);
    objConn.Close();
    GridView.DataSource = t;
    GridView.DataBind();
}

Затем во время события RowDataBound я кодирую данные следующим образом и привязываю эти данные к элементу управления asp: image:

protected void OnRowDataBound(object sender, GridViewRowEventArgs e)
{
    if (e.Row.RowType == DataControlRowType.DataRow)
    {
        DataRowView dr = (DataRowView)e.Row.DataItem;
        if(!String.IsNullOrEmpty(Convert.ToString(dr["thumbnailPhoto"])))
        {
            string imageUrl = "data:image/jpg;base64," + Convert.ToBase64String((byte[])dr["thumbnailPhoto"]);
            (e.Row.FindControl("Image1") as Image).ImageUrl = imageUrl;
        }
    }
}

С какой проблемой я здесь сталкиваюсь и как с ней бороться?

Я только что обнаружил, что те картинки, которые отображаются частично или с полосами, - это все картинки, которые хранятся в большем формате 600x600, в то время как хорошие имеют формат 96x96. Это приводит меня к подозрению, что что-то идет не так при получении thumbprintPhoto в шестнадцатеричном формате с помощью SQL.

Как предположил Габриэль, я попытался использовать DirectorySearcher. Отпечаток пальца был отображен правильно, но мне понадобилось более 10 секунд, чтобы получить 44 записи AD: Вот мой код

    protected void SearchAD(object sender, EventArgs e)
    {
        string Name = TextBoxSearchFirstName.Text;
        Name = Name.Replace("*", "") + "*";
        DirectorySearcher dsSearcher = new DirectorySearcher();
        dsSearcher.Filter = "(&(objectClass=user) (sn=" + Name + "))";
        results = dsSearcher.FindAll();

        DataTable t = new DataTable("ActiveDir");
        t.Columns.Add(new DataColumn("SecondName", System.Type.GetType("System.String")));
        t.Columns.Add(new DataColumn("FirstName", System.Type.GetType("System.String")));
        t.Columns.Add(new DataColumn("UserID", System.Type.GetType("System.String")));
        t.Columns.Add(new DataColumn("data", System.Type.GetType("System.Byte[]")));           

        if (results != null)
        {
            foreach (SearchResult searchResult in results)
            {
                DataRow myRow;
                myRow = t.NewRow();
                myRow[0] = searchResult.GetDirectoryEntry().Properties["sn"].Value;
                myRow[1] = searchResult.GetDirectoryEntry().Properties["givenName"].Value;
                myRow[2] = searchResult.GetDirectoryEntry().Properties["samAccountName"].Value;
                myRow[3] = searchResult.GetDirectoryEntry().Properties["thumbnailPhoto"].Value;
                t.Rows.Add(myRow);
            }
        }
        GridView1.DataSource = t;
        GridView1.DataBind();
    }

Решено: Габриэль настроил код поиска AD, и теперь он быстрее, чем SQL-запрос. Чтобы отображать изображения AD Thumnail Profil без использования обработчика, выполните декодирование во время события GridViews OnRowDataBound:

    protected void OnRowDataBoundAdUser(object sender, GridViewRowEventArgs e)
    {
        if (e.Row.RowType == DataControlRowType.DataRow)
        {
            DataRowView dr = (DataRowView)e.Row.DataItem;
            if (!String.IsNullOrEmpty(Convert.ToString(dr["data"])))
            {
                byte[] data = dr["data"] as byte[];
                MemoryStream s = new MemoryStream(data);
                byte[] imageBytes = s.ToArray();
                string base64String = Convert.ToBase64String(imageBytes);
                string imageUrl = "data:image/jpg;base64," + base64String;
                (e.Row.FindControl("Image1") as System.Web.UI.WebControls.Image).ImageUrl = imageUrl;
            }
        }
    }

1 Ответ

0 голосов
/ 14 мая 2018

Я понимаю, почему это так долго.DirectorySearcher и DirectoryEntry могут быть немного хитрыми из-за того, сколько раз они доходят до нашей эры.У вас гораздо больше сетевых запросов, чем нужно.

В вашем коде вы отправляетесь в AD один раз для поиска.Затем для каждого результата вы используете GetDirectoryEntry().Затем DirectoryEntry снова отправляется в AD при первом использовании Properties.Хуже того, как только вы используете Properties, он загружает каждый отдельный атрибут , который имеет значение, даже если вы на самом деле используете только 4 из них.Это большой бесполезный сетевой трафик.

Этого можно избежать, используя в результатах поиска коллекцию Properties, которая уже имеет все атрибуты (по умолчанию она получает каждый атрибут, имеющий значение).

Но вы можете сделать еще лучше: если вы установите PropertiesToLoad свойство DirectorySearcher, то оно будет возвращать только те значения, которые вы хотите использовать.Таким образом, у вас есть один сетевой запрос на все, что вы хотите, и только , что вы хотите.

protected void SearchAD(object sender, EventArgs e)
{
    string Name = TextBoxSearchFirstName.Text;
    Name = Name.Replace("*", "") + "*";
    var dsSearcher = new DirectorySearcher {
        Filter = "(&(objectClass=user) (sn=" + Name + "))"
    };
    dsSearcher.PropertiesToLoad.Add("sn");
    dsSearcher.PropertiesToLoad.Add("givenName");
    dsSearcher.PropertiesToLoad.Add("samAccountName");
    dsSearcher.PropertiesToLoad.Add("thumbnailPhoto");

    using (var results = dsSearcher.FindAll()) {
        var t = new DataTable("ActiveDir");
        t.Columns.Add(new DataColumn("SecondName", typeof(string)));
        t.Columns.Add(new DataColumn("FirstName", typeof(string)));
        t.Columns.Add(new DataColumn("UserID", typeof(string)));
        t.Columns.Add(new DataColumn("data", typeof(byte[])));

        foreach (SearchResult searchResult in results) {
            var myRow = t.NewRow();
            myRow[0] = searchResult.Properties.Contains("sn") ? searchResult.Properties["sn"][0] : null;
            myRow[1] = searchResult.Properties.Contains("givenName") ? searchResult.Properties["givenName"][0] : null;
            myRow[2] = searchResult.Properties.Contains("samAccountName") ? searchResult.Properties["samAccountName"][0] : null;
            myRow[3] = searchResult.Properties.Contains("thumbnailPhoto") ? searchResult.Properties["thumbnailPhoto"][0] : null;
            t.Rows.Add(myRow);
        }
    }
    GridView1.DataSource = t;
    GridView1.DataBind();
}

Несколько замечаний:

Звонки на Containsнеобходимы, потому что если атрибут пустой, то он вообще не существует в коллекции Properties.

Результаты поиска возвращают все как массив, независимо от того, находится он в AD или нет.Таким образом, [0] необходим для каждого атрибута.

Вы заметите, что я поместил оператор using вокруг результатов поиска.Это необходимо для предотвращения утечек памяти, в соответствии с документацией FindAll().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...