воскресенье, 9 декабря 2012 г.

CAML-запросы с расширенной фильтрацией по пользователям и группам

Давно забытое старое!
Речь сегодня пойдёт об использовании тега Membership в CAML-запросах.
Этого тега нет ни в CAML Builder ни в CAML Designer, поэтому не все знают о его существовании.
Тем не менее, на MSDN присутствует описание этого тега, хоть и без примеров.
Итак, запрос с использованием этого тега может выглядеть так:
<Where>
  <Membership Type='CurrentUserGroups'>
    <FieldRef Name='Person' />
  </Membership>
</Where>

Тег Membership содержит атрибут Type, указывающий тип фильтрации:
  • SPWeb.AllUsers – Выбор элементов, содержащих в указанном поле пользователя
  • SPWeb.Groups - Выбор элементов, содержащих в указанном поле группу
  • SPWeb.Users - Выбор элементов, содержащих в указанном поле пользователя, не содержащегося в группе 
  • CurrentUserGroups - Выбор элементов, содержащих в указанном поле группу, в которую входит текущий пользователь
  • SPGroup - Выбор элементов, содержащих в указанном поле указанную группу; группа (ID) указывается отдельным атрибутом тега Membership: ID=’1’

Пример.
Допустим имеем такой список:
image

Тестовое (консольное) приложение:
static void Main(string[] args)
{
    var values = new Dictionary<string, int>
        {
            {"SPWeb.AllUsers", 7},
            {"SPWeb.Groups", 7},
            {"SPWeb.Users", 7},
            {"CurrentUserGroups", 7},
            {"SPGroup", 1073741823}
        };

    foreach (var value in values)
        RunQuery(value.Key, value.Value);

    Console.WriteLine();
    Console.WriteLine("Completed!");
    Console.ReadKey(true);
}

static void RunQuery(string membership, int userId)
{
    using (var site = new SPSite("http://x33/", GetUserToken(userId)))
    {
        using (var web = site.OpenWeb())
        {
            var list = web.Lists["CAMLTest"];

            var query = new SPQuery {Query = string.Format("<Where><Membership Type='{0}' ID='4'><FieldRef Name='Person' /></Membership></Where>", membership)};
            var items = list.GetItems(query);

            Console.WriteLine("Current user: {0}; Membership type: {1}; Items count: {2}", web.CurrentUser.Name, membership, items.Count);
            items.Cast<SPListItem>().ToList().ForEach(li => Console.WriteLine("ID - {0}; Title - {1}; Person - {2}", li.ID, li.Title, li["Person"]));
            Console.WriteLine("----------");
            Console.WriteLine();
        }
    }
}

static SPUserToken GetUserToken(int userId)
{
    using (var site = new SPSite("http://x33/"))
    {
        using (var web = site.OpenWeb())
        {
            return web.SiteUsers.GetByID(userId).UserToken;
        }
    }
}

Результат работы приложения:
image

Наиболее интересный тип фильтрации: CurrentUserGroups.
Допустим в списке у нас проставлены группы. С помощью данного запроса мы можем выбрать все элементы, которые содержат группу текущего пользователя, т.е. элементы, доступные участником тех же групп, что и для текущего пользователя! (аналог фильтрации по аудиториям)

четверг, 20 сентября 2012 г.

Обзор get-параметров в адресах SharePoint

Решил собрать список возможных полезных get-параметров, которые иногда выручают при работе с SharePoint.
Просьба присылать другие найденные вами интересные параметры, их можно указывать в комментариях. Обязательно включу в пост. Заранее спасибо.

1. Contents=1 (http://site/default.aspx?contents=1). Переход к странице обслуживания веб-частей.
2. IsDlg=1 (http://site/default.aspx?IsDlg=1). Открытие страницы с использованием главной страницы (master page) minimal.master, т.е. без панели быстрого запуска, частично без ленты, шапки и т.п. Часто используется в диалоговых окнах.
image
3. Filter=1 (http://site/lists/AllItems.aspx?Filter=1). Открытие представления списка с выпадающими фильтрами полей.
image
4. ToolPaneView=2 (http://site/defailt.aspx?ToolPaneView=2). Открытие страницы с панелью добавления веб-частей. В зависимости от значения параметра открывается различная вкладка: 2 – Обзор, 3 – Поиск, 5 – Импорт.
image
5. DisplayMode=Design (http://site/default.aspx?DisplayMode=Design). Открытие страницы в режиме редактирования.
6. Mobile=1 (http://site/default.aspx?Mobile=1). Отображение в виде для мобильных устройств.
7. DeveloperDashboard=true (http://site/default.aspx?DeveloperDashboard=true). Отображение Developer Dashboard. (Должна быть включена возможность такого отображения: OnDemand).

Кроме этого, есть ещё Dynamic Link Libraries – библиотеки, указывая параметры которым можно получать различные результаты (owssrv.dll, admin.dll и другие). Подробнее о них можно найти в Overview of the SharePoint Team Services Architecture.

понедельник, 20 августа 2012 г.

Разбиение запроса SPQuery на страницы

Ещё один способ получить большое количество данных – это использовать разбиение запроса на страницы, т.е. получение элементов списка порциями по несколько элементов.

Для этого надо указать объекту класса SPQuery значения для свойств ListItemCollectionPosition и RowLimit.

RowLimit – указывает сколько элементов списка необходимо получить.

Свойство ListItemCollectionPosition – это объект класса SPListItemCollectionPosition принимающий в конструкторе строковой параметр, в котором указано с какого элемента необходимо получить данные (точнее следующего за ним элемента). Выглядит это так: “Paged=TRUE&p_ID=5” – получить элементы после элемента с ID равным 5.

Например, сделаем такой метод:

private static SPListItemCollection GetPagedItems(SPList list, string pagingInfo, uint rowLimit)
{

            var query = new SPQuery
                {
                    RowLimit = rowLimit,
                    ListItemCollectionPosition = new SPListItemCollectionPosition(pagingInfo)
                };
                    
            return list.GetItems(query);
}

 

Метод возвращает заданное количество элементов (rowLimit) из указанной страницы (pagintInfo).

Если в pagingInfo передавать пустую строку, то метод вернёт первую страницу.

Возвращаемые методом данные (типа SPListItemCollection) содержат в себе данные для получения следующей страницы – свойство ListItemCollectionPosition.

 

Таким образом, мы можем организовать постраничную загрузку и обработку элементов списка, например следующим образом (используя вышеприведённый метод):

using (var site = new SPSite("http://mysite/"))
{
    using (var web = site.OpenWeb())
    {
        var list = web.Lists["TestList"];

        var pagingInfo = string.Empty; //Здесь храним информацию о странице
        var pageNumber = 1; //Номер страницы, для оформления вывода
        SPListItemCollection items = null; //Полученные данные

        do
        {
            if (items != null && items.ListItemCollectionPosition != null)
                pagingInfo = items.ListItemCollectionPosition.PagingInfo; //Получаем данные о странице из предыдущего запроса

            Console.WriteLine("Page {0}, Info '{1}'", pageNumber, pagingInfo);

            items = GetPagedItems(list, pagingInfo, 5); //Получаем по 5 элементов
            foreach (SPListItem item in items)
                Console.WriteLine(item.Title);

            Console.WriteLine();
            pageNumber++;
        } while (items.ListItemCollectionPosition != null);
    }
}

 

Для моего списка результат выглядит следующим образом (консольное приложение):

image

пятница, 17 августа 2012 г.

Получение большого количества данных из SharePoint или использование ContentIterator

Как правило для получения данных из списков SharePoint мы используем SPQuery. Но если количество возвращаемых элементов велико, то мы можем получить SPQueryThrottleException.

Чтобы этого избежать, необходимо использовать появившийся в SharePoint 2010 класс ContentIterator!

Кроме элементов списков, он также умеет перебирать файлы, списки, сайты, коллекции сайтов, а также элементы или файлы в указанной папке.

Использовать данный класс предельно просто!

Пример:

using (var site = new SPSite("http://x33/"))
{
    using (var web = site.OpenWeb())
    {
        var list = web.Lists["TestList"];

        var itemsTitles = new List<string>();
        
        var iterator = new ContentIterator();
        iterator.ProcessListItems(list, spListItem => itemsTitles.Add(spListItem.Title), (spListItem, exception) => true);
    }
}

 

Методу ProceeListItems нужно указать два делегата – для обработки полученного элемента списка и для обработки ошибок при обращении к данным.

Класс находится в Microsoft.Office.Server.Utilites.

При необходимости ему также можно указать SPQuery, чтобы выбирать только нужные элементы.

Методы перебора других сущностей SharePoint аналогичны.

воскресенье, 22 июля 2012 г.

Internet Explorer 10: открытие последних вкладок при запуске

Таки свершилось! Сколько лет (скорее десятков) ждали!

IE (версии 10) теперь умеет сохранять вкладки при закрытии и открывать их при запуске!

IE10 IE10Eng

По умолчанию данное поведение выключено, необходимо включать в параметрах самостоятельно.

четверг, 19 июля 2012 г.

Ошибка при установке Prerequisites для SharePoint 2013

В самом начале установки Prerequisites для SharePoint 2013 столкнулся с ошибкой:

image

Ошибка установки ролей сервера приложений и веб-сервера.

Обзор журнала (Review the log file) показал, что происходит запуск нескольких команд. Последней из которых оказалась:

"C:\Windows\system32\cscript.exe" "C:\Windows\system32\iisext.vbs" /enext "ASP.NET v4.0.30319"

Пробую её отдельно, и получаю ошибку:

“Error while configuration application or extention.

The extention does not exist in the restriction list.”

При чём, при попытке заменить v4.0.30319 на v2.0.50727 ошибки не возникло.

Поиск по самому тексту ошибки ничего не дал, но к месту, где нужно копать всё же привёл.

 

Итак, решение.

Заходим в Диспетчер IIS (Установщик саму роль должен был установить), идём ветке локального веб-сервера и переходим к пункту Ограничения ISAPI и CGI (ISAPI or CGI Restrictions):

image

Видим два пункта, относящихся к ASP.NET v4.0.30319, но имеющих немного другие имена (с постфиксом 32-bit).

Соответственно решение и состоит в том, чтобы переименовать данные пункты в нужное имя.

image