Wednesday 21 December 2016

Управление большими списками и библиотеками в SharePoint

Управление большими списками и библиотеками в SharePoint очень актуальная и востребованная тема, как для администраторов, так и для программистов. 
И, если для администратор SharePoint в сети опубликовано достаточно качественного (ну, качество материала суждение субъективное😆, и я об этом немного после порассуждаю) справочного материала, например этот, то программистам немного сложнее изыскать соответствующий материал. 
Более того,  подходы к работе с большими данными в SharePoint Online и SharePoint 2013 (2016) разный. Об этом, кстати, совершенно справедливо сказано в этой статье.
Сегодня я планирую описать свой опыт при работе с большими данными в SharePoint 2013 с использованием Business Connectivity Services (BCS) компонентов на стороне сервера.

Да, именно в этом случае проблемы работы с большими объемами списков или библиотек наиболее актуальны, так как приходиться самостоятельно формировать запрос к источнику данных. 
Известно, что в SharePoint 2013(2016) и SharePoint Online существуют пороговое ограничение получения списка или библиотеки в 5000 элементов, которое можно регулировать. В SharePoint Online возможность регулирования порогового ограничения отсутствует. В случае, если представление списка или библиотеки возвращает число элементов большее порогового ограничения, то будет сгенерировано  исключение.
Вот теперь подробнее о том, как следует построить решение (SPSolution) SharePoint, которое будет запрашивать большое число элементов и не создавать исключений превышения порогового значения, установленного администратором портала☺:
Мы не будем обсуждать варианты увеличения порогового знания на глобальном уровне в центре администрирования. Как известно, по умолчания это 5000 элементов.


Потому как любое увлечения порогового значения проблему решит на локальном уровне, но одновременно с этим может снизить производительность портала SharePoint в целом. Кроме этого, это единственный вариант, который доступен администраторам портала SharePoint, у программистов же возможности гораздо больше.

Первый вариант. Свойство QueryThrottleMode класса SPQuery

Перечислитель QueryThrottleMode содержит 3 варианта использования:
1. Default
2. Override
3. Strict
Для нас интересен параметр Override. Как сказано в документации - "Значение перечисления для переопределения: 1. Если пользователь является локальным администратором на сервере без ограничения полосы пропускания будет применяться в запросе. Если политика безопасности приложения web предоставляет разрешения чтение или полный доступ пользователя предел регулирования для аудиторов и администраторов будет применяться к числа элементов, включенных в запрос и регулирование не будет применяться к число подстановки, пользователей или групп и полей состояния рабочего процесса. В противном случае параметр [Microsoft.SharePoint.SPQueryThrottleOption.SPQueryThrottleOption.Default] применяется к запросу."
На практике перечислитель QueryThrottleMode используется следующим образом (снятие ограничения на уровне запросов):
//создаем ссылку на список
SPList list = web.Lists["ListName"];
//создаем запрос
SPQuery query = new SPQuery();
query.Query = @"<View Scope='RecursiveAll'>
               <ViewFields>
                  <FieldRef Name='ID' />
                  <FieldRef Name='Title' />                                                                 
               </ViewFields> 
               <Query>
                  <Where>
                     <Eq>
                        <FieldRef Name='Title' /><Value Type='Text'>текст для фильтра</Value>
                     </Eq>
                  </Where>  
                </Query>                            
                </View>";
//меняем перечислить запроса
query.QueryThrottleMode = SPQueryThrottleOption.Override;
//создаем ссылку на массив строк 
SPListItemCollection results = list.GetItems(query);
//далее используем переменную results по назначению, например так
foreach (SPListItem item in results)
{
//здесь ваш код....👧  
}
Вот и все. Следует добавить, что данный код будет работать, как следует только тогда, когда запрос выполняет пользователь с привилегированными правами. Это администраторы ферм или те, кому предоставлен полный доступ к запрашиваемым ресурсам. Не очень удобная ситуация, да 😆, тем более, эти пользователи и так имеют привилегии для просмотра ресурсов, предоставленные им методами регулирования ресурсов в центре администрирования портала. И поэтому, указанные выше метод, мягко говоря непрактичен 😄😄😄😄😄😄. 
Конечно, программисты SharePoint, могут обернуть код в конструкцию SPSecurity.RunWithElevatedPrivileges и тогда все запросы будут осуществляться от имени администратора портала. Но и это, не очень умное решения, хотя бы с точки зрения производительности и безопасности запросов😂.  Но не все так печально, так как у нас имеется вариант № 2 😆

Второй вариант ContentIterator:

Класс ContentIterator предоставляет методы для выполнения запросов элементов списка, списков и веб-узлов для регулирования объема передаваемых данных (т.е., чтобы избежать возникновения SPQueryThrottledException).
В справке класса приведен небольшой пример его использования. Поэтому я не буду ссылаться на код из своей практики. Они, практически идентичны. Замечу только, что путем опытных экспериментов я выяснил, что для меня класс не совсем приемлем, ну, хотя бы потому, что у меня с помощью этого класса не получилось "практично" запросить данные списка по нескольким столбцам. "Выдача" осуществляется только по одному столбцу. И этот столбец точно не может иметь тип Note. Поэтому я представлю третий вариант, который на мой взгляд, самый "практичный", по крайней мере. для меня😄😄😄😄😄😃😜

Третий вариант BatchQueryExector:

Итак, меня не устроил первый вариант и второй вариант, следовательно нужно мастерить нечто среднее между ними, позаимствовав у них все самое лучшее 😃. Я обратился за помощью к google, который привел меня к статье автор Charles Chen. Там описан класс, который и выполняет всю работу, так как это хотел я. Если коротко - класс запрашивает строки списков постранично. В общем ничего нового в подходах в работе с SQL данными, только подход перенесен на посредника😅. Я практически ничего не менял в классе, кроме метода GetItems. В моем варианте он выглядит так:
            /// <summary>
            ///     Извлекает элементы в списке в пакетах, основанных на <c>RowLimit</c> и 
            ///     вызывает обработчик для каждого элемента.
            /// </summary>
            /// <param name="handler">Метод, который вызывается для каждого элемента.</param>
            public void GetItems(Action<SPListItem> handler, bool Single = false)
            {
                string pagingToken = string.Empty;
 
                while (true)
                {
                    _query.ListItemCollectionPosition = new SPListItemCollectionPosition(pagingToken);
 
                    SPListItemCollection results = _list.GetItems(_query);
 
                    foreach (SPListItem item in results)
                    {
                        handler(item);
                    }
 
                    if (results.ListItemCollectionPosition == null || Single)
                    {
                        break// EXIT; no more pages.
                    }
                    pagingToken = results.ListItemCollectionPosition.PagingInfo;
                } 
            } 
Я думаю, что тот, кто сравнит исходник с моим вариантом, поймет "в чем новшество" и зачем?😃😏
Здесь я приведу пример использования класса. Пример из реального решения без ретуши и изменений😃:

Первый, где нужно получить только одну строку

            using ( SPSite siteNew = new SPSite ( this.SiteName ) )
            {
                using ( SPWeb webNew = siteNew.OpenWeb ( ) )
                {
                    try
                    {
                        string title = "";
                        SPList list = webNew.Lists[MConst.MFC_WikiChita_BZnaniy];//находим список                                               
                        SPQuery query = QueryBZnaniy.GetQuery(Single:true, ID: id);                                                
                        BatchQueryExector.WithQuery(query).OverList(list).GetItems(item => 
                        {
                            if (item != null)
                            {
                                title = item.Title;
                            }
                        },true);
                        return title;
                    }
                    catch (Exception e)
                    {
                        perror.Visible = true;
                        perror.CssClass = "padding-10 ui-state-error";
                        lerror.Text = e.ToString();
                        SendEmail.SendErr(webNew, e.ToString());
                        return "null";
                    }
                    finally
                    {
                        if (webNew != null)
                            webNew.Dispose();
                    }
                }
            }

Второй, где надо получить массив строк:

            using ( SPSite siteNew = new SPSite ( this.SiteName ) )
            {
                using ( SPWeb webNew = siteNew.OpenWeb ( ) )
                {
                    try
                    {
                        SPList list = webNew.Lists[MConst.MFC_WikiChita_BZnaniy];//находим список                                                  
                        var query = QueryBZnaniy.GetQuery();
                        List<BZnaniy> it = new List<BZnaniy> ( );
                        BatchQueryExector.WithQuery(query).OverList(list).GetItems(item =>
                        {
                            if (item != null)
                            {
                                SPFieldUrlValue fieldValue = 
new SPFieldUrlValue(item["URL"].ToString());
                                SPFieldUrlValue URL_BZ_Site = 
new SPFieldUrlValue(item["URL_BZ_Site"] != null ? item["URL_BZ_Site"].ToString() : null);
                                string title = 
item["Title"] != null && !string.IsNullOrEmpty(item["Title"].ToString()) ? 
item["Title"].ToString().ToUpper() : "[нет данных]";                                
                                it.Add(new BZnaniy
                                {
                                    id = item.ID,
                                    Title = title,
                                    UrlImage = fieldValue != null ? fieldValue.Url : "#",
                                    UrlSite = 
URL_BZ_Site != null && !string.IsNullOrEmpty(URL_BZ_Site.Url) ? 
URL_BZ_Site.Url : this.Page.Request.Url.AbsolutePath + "?BZnaniyId=" + item.ID;
                                });      
                            }
                        });                                                
                        return it;
                    }
                    catch ( Exception e )
                    {
                        perror.Visible = true;
                        perror.CssClass = "padding-10 ui-state-error";
                        lerror.Text = e.ToString ( );
                        SendEmail.SendErr(webNew, e.ToString());
                        return new List<BZnaniy> ( );
                    }
                    finally
                    {
                        if (webNew != null)
                            webNew.Dispose();
                    }
                }
            }
В реальном решении третий вариант работы с большими данными прекрасно себя зарекомендовал. Единственное замечание - пожалуйста, не забывайте индексировать столбцы списков или библиотек, которые участвуют в фильтрах запросов. Ну, это стандартные рекомендации😃. Они актуальные и разумные для всех случаев😃😃😃😃😃😃  

Tuesday 15 November 2016

Мастер назначения полномочий исполняющим обязанности

На порталах, сделанных в SharePoint, кроме прочего, очень гибкая и надежная система авторизации и профилей пользователей. Данная система удобна для больших и средних (и даже маленьких 😶) организаций, у которых допуск к ресурсам регламентируются должностными обязанностями сотрудников.
Часто происходят случаи, когда должностные лица, у которых уровни доступа к ресурсам разные, замещают друг друга. И тогда администратору портала следует выполнить вручную определенные действия, чтобы замещающие обязанности лица получили доступ к ресурсам на время выполнения таких обязанностей.
Для перераспределения обязанностей между сотрудниками организации мною и был создан мастер "Мастер передачи прав и обязанностей".
Это решение для фермы, которое выполняется в следующей последовательности:
1. Если необходимо править права на портале:
Пользователь создает в мастере задачу на передачу прав. При этом указывает: роль, которую следует править и период передачи прав.
2. Если необходимо передать обязанности по задачам:
Здесь пользователю предлагается выбрать имена задач, по которым он является ответственным и которые на время работы с мастером еще не окончены. Или "приказать" "мастеру" искать самостоятельно все его незакрытые задачи на портале.
3. Если необходимо передать управление несогласованными документами:
Здесь, по аналогии с задачами. Только вместо задач "мастер" будет работать с документами.
После того, как пользователь создает соответствующую задачу в "мастере", в работу вступает "робот". Он ежедневно читает список задач "мастера", и если находит для себя работу, то выполняет ее. Например, он может либо отредактировать указанные ему роли пользователей портала, или переписать задачи или документы на указанного ему исполнителя. 
Все очень просто. "Робот" в автоматическом режиме выполняет работу администратора портала, который в свою очередь "курит бамбук" 😶 или еще что-либо 😶😶😶

Некоторые скриншоты "мастера":









Если вас заинтересовал материал, то я обязуюсь ответить на ваши вопросы и (или) оказать практическую помощь при создании аналогичного решения для вашей фермы SharePoint.
😶😶😶😶😶😶😶😶😶

Sunday 9 October 2016

База знаний многофункционального центра

В отличие от форума, где можно обсудить новости, предложения и задать интересующие вопросы, база знаний - скорее справочник, в котором в простой и понятной форме зафиксированы факты, пошаговые инструкции и рекомендации.
В многофункциональных центрах база знаний создается для обучения сотрудников и повышения их квалификации.
Сегодня будет представлена структура реально существующей базы знаний и ее описание.
Схема отношений объектов базы знаний


Требование к программному обеспечению:
1
Платформа
SharePoint  2013
2
Приложение
1.      Решение для фермы (хранение бизнес процессов)
2.      Изолированное решение (хранение списков и библиотек)
3
Контейнер для HTML верстки
Веб часть
4
Бизнес-процессы
Код на C#
5
Хранилище для данных
Списки и библиотеки SharePoint
 Решаемые задачи:
База знаний – комплекс решений SharePoint, предназначенных для выполнения следующих задач:
1.    Пополнение Базы знаний
2.    Редактирование Базы знаний
3.    Организация доступа к Базе знаний для сотрудников МФЦ в соответствии с правилами «Системы ролей Базы знаний»
4.    Разделение обязанностей между редакторами Базы знаний в соответствии с правилами «Системы ролей Базы знаний»
Система ролей Базы знаний
В решении используются три роли:
1.     Все пользователи портала
2.     Младшие управляющие БЗ
3.     Старшие управляющие БЗ
Наименование роли
Действия
Объект
1
Все
Чтение
Список MFC_WikiChita_BZnaniy
Чтение
Список MFC_WikiChita_MList
Чтение
Список MFC_WikiChita_Organ
Чтение
Список MFC_WikiChita_OrganDetail
Чтение
Список MFC_WikiChita_Statistic
Чтение
Список MFC_WikiChita_Uslugi
Чтение
Список MFC_WikiChita_UslugiDetail
Чтение
Список MFC_WikiChita_UslugiInvisible
Чтение
Библиотека MFC_WikiChita_Soglasheniy
Чтение
Библиотека MFC_WikiChita_Blanki
2
Младший управляющий БЗ
Чтение
Список MFC_WikiChita_BZnaniy
Чтение
Список MFC_WikiChita_MList
Чтение
Список MFC_WikiChita_Organ
Чтение, Совместное использование
Список MFC_WikiChita_OrganDetail
Чтение
Список MFC_WikiChita_Statistic
Чтение
Список MFC_WikiChita_Uslugi
Чтение, Совместное использование
Список MFC_WikiChita_UslugiDetail
Чтение, Совместное использование
Список MFC_WikiChita_UslugiInvisible
Чтение
Библиотека MFC_WikiChita_Soglasheniy
Чтение, Совместное использование
Библиотека MFC_WikiChita_Blanki
2
Старший управляющий БЗ
Чтение, Совместное использование
Список MFC_WikiChita_BZnaniy
Чтение, Совместное использование
Список MFC_WikiChita_MList
Чтение, Совместное использование
Список MFC_WikiChita_Organ
Чтение, Совместное использование
Список MFC_WikiChita_OrganDetail
Чтение
Список MFC_WikiChita_Statistic
Чтение, Совместное использование
Список MFC_WikiChita_Uslugi
Чтение, Совместное использование
Список MFC_WikiChita_UslugiDetail
Чтение, Совместное использование
Список MFC_WikiChita_UslugiInvisible
Чтение, Совместное использование
Библиотека MFC_WikiChita_Soglasheniy
Чтение, Совместное использование
Библиотека MFC_WikiChita_Blanki

Хранилище БД. Списки и библиотеки Решения
Имя
Назначение
1
MFC_WikiChita_BZnaniy
Список, предназначен для хранения наименований территориальных органов МФЦ. В некоторых случаях список может именоваться, как БЗ.
2
MFC_WikiChita_MList
Список, предназначен для хранения служебной информации, используемой системой организации бизнес-процессов Решения. В частности, это касается хранения вторичных ключей от органов и баз знаний. В последующем система организации бизнес-процессов должна гарантировать ссылочную целостность между указанными списками.
3
MFC_WikiChita_Organ
Список, предназначен для хранения информации об органах, оказывающих муниципальные или государственные услуги.
4
MFC_WikiChita_OrganDetail
Список, предназначен для хранения информации о территориальных подразделениях  органов (их филиалы).
5
MFC_WikiChita_Uslugi
Список, предназначен для хранения информации об именах услугах, а также ссылок на бланки услуг и контейнера для вопросов и ответов по услуге.
6
MFC_WikiChita_UslugiDetail
Список, предназначен для хранения информации об услуге.
7
MFC_WikiChita_UslugiInvisible
Список, предназначен для хранения служебной информации, используемой системой организации бизнес-процессов Решения. В частности, это касается хранения вторичных ключей от услуг и баз знаний. В последующем система организации бизнес-процессов должна гарантировать ссылочную целостность между указанными списками.
8
MFC_WikiChita_Statistic
Список, предназначен для хранения информации о просмотрах Базы знаний сотрудниками МФЦ.
9
MFC_WikiChita_Soglasheniy
Библиотека, предназначена для хранения документов – соглашений между МФЦ и органами, оказывающими государственные или муниципальные услуги.
10
MFC_WikiChita_Blanki
Библиотека, предназначена для хранения документов – бланков для услуг.

Организация бизнес-процессов
Бизнес-процесс обязан:
1.     Гарантировать установку решений Баз знаний на любом сайте Портала МФЦ и выполнения ими задач в полном объеме независимо друг от друга, в тоже время, подчиненным единым требованиям и правилам и способным выдавать результаты, как единое целое, например, при сборе статистики о просмотрах Базы знаний сотрудниками МФЦ.  
2.     Контролировать ссылочную целостность между:
2.1. Базой знаний и органами. У одной базы знаний может быть несколько органов. Система должна запрещать удаление базы знаний, если к ней прикреплен хотя бы один орган.
2.2.Орган и услуги.   У одного органа может быть несколько услуг. Система должна запрещать удаление органа, если к нему прикреплена хотя бы одна услуга.
2.3.Услуга и описание услуг. У услуги может быть несколько описаний. Система должна запрещать удаление услуги, если к ней прикреплено хотя бы одно описание.
2.4.Орган и подчиненные органы. У одного органа может быть несколько подчиненных органов. Система должна запрещать удаление органа, если к нему прикреплен хотя бы один подчиненный орган.
3.     Контролировать процесс пополнения и редактирования Базы знаний в соответствии с требованием системы ролей.
4.     Организовывать процесс взаимодействия форм редакторов списков базы знаний с Веб частью решения в «один клик». А именно – гарантировать возврат на место вызова редакторов после успешного создания или редактирования строки у списка.
5.     Гарантировать наличие интернет адреса у каждой услуги Базы знаний. Интернет адрес услуги (в пределах портала МФЦ), по необходимости, может быть включен в ссылку на услугу в любых документах МФЦ. По ссылке пользователи портала МФЦ должны получать доступ к полной информации об услуге в «один клик» без дополнительных действий.
6.     Гарантировать ведение статистики просмотров базы знаний сотрудниками МФЦ. По необходимости, формировать отчет о просмотрах. Структура отчета оговаривается дополнительно. Статистика в части старших и младших редакторов баз знаний, а также администраторов портала МФЦ, не ведется.
7.     Гарантировать редакторам Базы знаний возможность уведомления сотрудников МФЦ об услуге по корпоративной почте МФЦ в «один клик», в случае ее обновления или по другим любым основаниям.
8.     Гарантировать сотрудникам МФЦ возможность уведомления редакторов Базы знаний об услуге по корпоративной почте МФЦ в «один клик», например, в случае обнаружения в ней недостатков.
9.     Гарантировать установку Веб части Базы знаний в любом месте портала МФЦ в неограниченном количестве.
10.  Гарантировать следующие принципы работы Базы знаний:
10.1.      Каждая БЗ имеет собственные, прикрепленные к ней органы, свойства которых наследуются от первоисточника. Изменения любого свойства в органе в любой БЗ изменяют первоисточник и затрагивают все БЗ, куда прикреплен орган 
10.2.      Каждый орган может наследовать, прикрепленные к нему услуги из других БЗ, при этом, наследование услуги может быть прекращено в любое время, тогда орган теряет право на управление ранее унаследованной услугой. Кроме этого, каждый орган может иметь собственные услуги, индивидуальные только для этого органа, прикрепленного к конкретной БЗ.
10.3.      Каждая услуга может наследовать, прикрепленные к ней описания из других БЗ, при этом, наследование описания может быть прекращено в любое время, тогда услуга теряет права на управления ранее унаследованным описанием. Кроме этого, каждая услуга может иметь собственные описания, индивидуальные только для этой услуги, прикрепленной к конкретной БЗ.
10.4.      Описания услуг могут быть созданы в БЗ на основании предопределенных наименований:
10.4.1.  Ответственный орган
10.4.2.  Получатель услуги
10.4.3.  Перечень предоставляемых документов
10.4.4.  Максимально допустимый срок предоставления услуги
10.4.5.  Результат предоставления услуги
10.4.6.  Основания для отказа  в приеме документов
10.4.7.  Основания для отказа в предоставлении услуги
10.4.8.  Реквизиты для оплаты
10.4.9.  Предоставление услуги регламентируется
10.4.10.        Рабочие контакты
10.4.11.        Срок хранения документов
10.4.12.        Прочее
По необходимости, описание услуг могут иметь и другие наименования.

10.5.      Контейнер для описания услуг должен помещать в себя неограниченный объем текста, ничем неограниченную структуру текста, например, текст может быть в виде – таблицы или разного рода списков. Контейнер для описания услуг должен быть снабжен редактором HTML.

Некоторые скриншоты  рабочего решения

список баз знаний
Список Баз знаний


Услуга - первая страниц
Список описаний услуги
Описание услуги