Показаны сообщения с ярлыком 2010. Показать все сообщения
Показаны сообщения с ярлыком 2010. Показать все сообщения

понедельник, 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 аналогичны.

суббота, 19 мая 2012 г.

Получение данных об изменениях на сайте - использование SPChangeQuery

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

Для осуществления запроса вызывается метод .GetChanges() объекта SPSite, SPWeb, SPList или SPContentDatabase.

 

Рассмотрим возможные отслеживаемые действия:

var query = new SPChangeQuery(false, false)
                {
                    Add = true, // Добавление объекта
                    Delete = true, // Удаление объекта
                    Update = true, // Обновление объекта
                    SystemUpdate = true, // Системное обновление элемента
                    GroupMembershipAdd = true, // Добавление пользователя в группу
                    GroupMembershipDelete = true, // Добавление пользователя в группу
                    Move = true, // Перемещение объекта
                    Rename = true, // Переименование объекта
                    Restore = true, //Восстановление объекта из корзины или архивной копии
                    RoleAssignmentAdd = true, // Назначение роли пользователю или группе
                    RoleAssignmentDelete = true, // Удаление роли
                    RoleDefinitionAdd = true, // Назначение разрешений роли
                    RoleDefinitionDelete = true, // Удаление разрешений роли
                    RoleDefinitionUpdate = true, // Обновление разрешений роли
                };

и возможные отслеживаемые объекты:

var query = new SPChangeQuery(false, false)
                {
                    Alert = true, // Оповещения
                    ContentType = true, // Типы содержимого
                    Field = true, // Поля списка
                    File = true, // Файлы
                    Folder = true, // Папки
                    Group = true, // Группы
                    Item = true, // Элементы списков
                    List = true, // Списки
                    Navigation = true, // Элементы навигации
                    SecurityPolicy = true, // Политики безопасности
                    Site = true, // Коллекция сайтов
                    User = true, // Пользователи
                    View = true, // Представления списков
                    Web = true, // Сайт
                };

Также позволяет задавать начальную (ChangeTokenStart) или конечную (ChangeTokenEnd) дату возвращаемых изменений.

 

Пример использования:

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

        var query = new SPChangeQuery(false, false)
                        {
                            FetchLimit = 500, // Limit
                            Item = true, // Object type
                            Add = true, // Change type
                            Delete = true, // Change type
                            Update = true, // Change type
                            ChangeTokenStart = new SPChangeToken(SPChangeCollection.CollectionScope.List, list.ID, new DateTime(2012, 05, 11)) //From date
                        };

        Console.WriteLine("{0,-20}{1, -10}{2}", "Title/ID", "Action", "Time");

        while (true)
        {
            var changes = list.GetChanges(query);

            foreach (var change in changes.OfType<SPChangeItem>())
            {
                string itemTitle;
                try
                {
                    itemTitle = "Item Title: " + list.Items.GetItemById(change.Id).Title;
                }
                catch (Exception)
                {
                    itemTitle = "Item Id: " + change.Id;
                }

                Console.WriteLine("{0,-20}{1, -10}{2}", itemTitle, change.ChangeType, timeZone.UTCToLocalTime(change.Time));
            }

            // Go to next batch or break
            if (changes.Count < query.FetchLimit)
                break;
            query.ChangeTokenStart = changes.LastChangeToken;
        }
    }
}

 

Результат работы программы (консольное приложение):

image

четверг, 3 мая 2012 г.

Программное создание страниц веб-частей

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

Решать её необходимо с помощью ProcessBatchData:

/// <summary>
/// Create new webpart page
/// </summary>
/// <param name="list">List to keep page</param>
/// <param name="pageTitle">Page title</param>
/// <param name="layoutTemplate">Layout template id</param>
/// <returns></returns>
private static string CreateWebPartPage(SPList list, string pageTitle, int layoutTemplate)
{
    const string newItemTemplate = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
                                    "<Method ID=\"0,NewWebPage\">" +
                                    "<SetList Scope=\"Request\">{0}</SetList>" +
                                    "<SetVar Name=\"Cmd\">NewWebPage</SetVar>" +
                                    "<SetVar Name=\"ID\">New</SetVar>" +
                                    "<SetVar Name=\"Type\">WebPartPage</SetVar>" +
                                    "<SetVar Name=\"WebPartPageTemplate\">{2}</SetVar>" +
                                    "<SetVar Name=\"Overwrite\">true</SetVar>" +
                                    "<SetVar Name=\"Title\">{1}</SetVar>" +
                                    "</Method>";
    var newItemXml = string.Format(newItemTemplate, list.ID, pageTitle, layoutTemplate);

    return list.ParentWeb.ProcessBatchData(newItemXml);
}

 

Применение:

var web = SPContext.Current.Web;
var pagesLibrary = web.GetList("Pages");
CreateWebPartPage(pagesLibrary, "MyPage", 2);

Номера шаблонов для LayoutTemplate:

  1. Целая страница, по вертикали
  2. Верхний колонтитул, нижний колонтитул, 3 столбца
  3. Верхний колонтитул, левый столбец, текстовая область
  4. Верхний колонтитул, правый столбец, текстовая область
  5. Верхний колонтитул, нижний колонтитул, 2 столбца, 4 строки
  6. Верхний колонтитул, нижний колонтитул, 4 столбца, верхняя строка
  7. Левый столбец, верхний колонтитул, нижний колонтитул, верхняя строка, 3 столбца
  8. Правый столбец, верхний колонтитул, нижний колонтитул, верхняя строка, 3 столбца

или тут.

пятница, 30 марта 2012 г.

Redirect из EventReceiver’а

Как оказалось, это довольно частая задача. Но практически нигде не разрешённая.
Итак, у нас есть обработчик события создания элемента списка (ItemAdding); и нам необходимо сразу после создания перейти на другую страницу.

На первый взгляд задача простая: у нас есть и «Page.Response.Redirect(…)» и «SPUtility.Redirect(…)».
Но… Для первого случая у нас нет объекта Page! А второй метод требует указания HttpContext, который в обработчиках события пуст.

Решение!
Как всегда хак! :)

Как известно, создание элементов списка можно отменять (для этого обработчики событий видимо изначально и создавались). При этом, отменяя, мы можем указать адрес, на который нам следует перейти (чтобы посмотреть причину отмены) (доступно только в SharePoint 2010).
То есть, мы можем отменить создание элемента, и сделать искомый редирект на нужную страницу. Нам нужно только пересоздать отменённый элемент. Вот тут и кроется ограничение этого метода – у нас нет доступа к вложениям элемента при его создании.

Пример кода реализации данного метода:

public override void ItemAdding(SPItemEventProperties properties)
{
    base.ItemAdding(properties);

    //Отключаем сам обработчик, чтобы избежать зацикливания
    EventFiringEnabled = false;

    var list = properties.List;

    //Создаём элемент списка и заполняем его свойствами из только что созданного пользователем элемента
    var ni = list.Items.Add();

    //Выбираем все созданные пользователем свойства доступные для редактирования, а также свойство Title (Название)
    foreach (var ff in list.Fields.Cast<SPField>().Where(spf => !spf.ReadOnlyField && (spf.FromBaseType == false || spf.InternalName == "Title")))
        ni[ff.InternalName] = properties.AfterProperties[ff.InternalName];
    ni.SystemUpdate();

    //Включаем обработчик
    EventFiringEnabled = true;

    //Отменяем создание элемента созданного пользователем
    properties.Cancel = true;
    //Устанавливаем действие при отмене - переход на другую страницу
    properties.Status = SPEventReceiverStatus.CancelWithRedirectUrl;
    //Устанавливаем адрес страницы, на которую делаем переход. В данном случае - страница редактирования только что созданного элемента
    properties.RedirectUrl = string.Format("/{0}?ID={1}", properties.List.Forms[PAGETYPE.PAGE_EDITFORM].Url, ni.ID);
}

Событие ItemAdded для этого метода не подходит, т.к. там элемент списка уже создан и отменить это действие уже нельзя.

пятница, 13 января 2012 г.

Работа с тегами и заметками (комментариями)


Теги и заметки позволяют помечать страницы сайта SharePoint общедоступными соответственно тегами и комментариями.
Данные социальные объекты приписываются к определённому адресу и содержат в себе заголовок (не отображается на сайте), содержимое и владельца (создателя).
Программный доступ к ним осуществляется через объекты SocialTagManager и SocialCommentManager, а также объект SocialRatingManager для рейтинга. Далее будем рассматривать работу с комментариями, работа с тегами и рейтингом реализовывается аналогичным образом.

Получение списка комментариев. Рассмотрим следующий метод:
using (var site = new SPSite(SPContext.Current.Site.ID))
{
    var spServiceContext = SPServiceContext.GetContext(site);
    var socialContextManager = new SocialCommentManager(spServiceContext);
    var comments = socialContextManager.GetComments(new Uri("http://mysite/default.aspx", UriKind.Absolute));
}

Проблемы приведённого кода в том, что он позволяет получить комментарии только определённого пользователя. Для получения всех комментариев всех пользователей для определённого Url необходимо произвести операцию обнуления контекста! Например, следующим образом:
using (var site = new SPSite(SPContext.Current.Site.ID))
{
    var httpContext = HttpContext.Current;
    try
    {
        var spServiceContext = SPServiceContext.GetContext(site);
        var currentWeb = SPContext.Current.Web;
        HttpContext.Current = null; //Обнуляем текущий контекст
        var socialContextManager = new SocialCommentManager(spServiceContext);
        var comments = socialContextManager.GetComments(new Uri("http://mysite/default.aspx", UriKind.Absolute));
    }
    finally
    {
        HttpContext.Current = httpContext; //Восстанавливаем текущий контекст
    }
}

Добавление нового комментария. Пожалуй, единственная операция, которая работает без дополнительных костылей! J
var spServiceContext = SPServiceContext.GetContext(SPContext.Current.Site); //Получение контекста
var socialContextManager = new SocialCommentManager(spServiceContext); //Создание объекта менеджера комментариев
socialContextManager.AddComment(new Uri("http://mysite/default.aspx", UriKind.Absolute), "Мой комментарий!", false, "Заголовок комментария"); //Создание и добавление комментария

Изменение и удаление комментария. Рассмотрим код:
using (var site = new SPSite(SPContext.Current.Site.ID))
{
    var spServiceContext = SPServiceContext.GetContext(site); //Получаем контекст
    var socialContextManager = new SocialCommentManager(spServiceContext);
    var comments = socialContextManager.GetComments(new Uri("http://mysite/default.aspx", UriKind.Absolute)); //Получаем список комментариев

    comments[0].Comment = "Изменённый комментарий"; //Изменяем комментарий
    comments[0].Update(); //Применяем изменения

    comments[1].Delete(); //Удаляем комментарий
}

Проблема данного кода, в том, что таким образом можно удалить только «свои» комментарии, т.е. те которые созданы текущим пользователем. Для удаления комментариев, созданных другими пользователями, необходимо изменить текущего пользователя в контексте. Сделать это можно используя рефлексию:
var siteUrl = SPContext.Current.Site.Url;
using (var site = new SPSite(siteUrl))
{
    var socialCommentManager = new SocialCommentManager(SPServiceContext.GetContext(HttpContext.Current));
    var comments = socialCommentManager.GetComments(CommentsControl.CurrentUri).ToList(); //Получаем список комментариев
    var commentOwner = comments[0].Owner["AccountName"].ToString(); //Получаем логин пользователя создавшего комментарий
   
    using (var web = site.OpenWeb())
    {
        var user = web.EnsureUser(commentOwner);//Получаем нужного пользователя
        web.AllowUnsafeUpdates = true;
        var request = new HttpRequest("", siteUrl, "");
        HttpContext.Current = new HttpContext(request, new HttpResponse(new StringWriter(CultureInfo.CurrentCulture)));
        HttpContext.Current.Items["HttpHandlerSPWeb"] = web;
        var identity = WindowsIdentity.GetCurrent(); //Получаем сущность текущего пользователя
        typeof (WindowsIdentity).GetField("m_name", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(identity, user.LoginName);
        HttpContext.Current.User = new GenericPrincipal(identity, new string[0]); //Изменяем текущего пользователя текущего контекста

        var socialCommentManager2 = new SocialCommentManager(SPServiceContext.GetContext(HttpContext.Current));
        var commentsList = socialCommentManager.GetComments(CommentsControl.CurrentUri).ToList(); //Получаем список комментариев

        commentsList[0].Comment = "Изменённый комментарий"; //Изменяем комментарий
        commentsList[0].Update(); //Применяем изменения

        web.AllowUnsafeUpdates = false;
    }
}

Если нужно изменить/удалить все комментарии всех пользователей, то придётся вызывать вышеприведённый код отдельно для каждого пользователя.

Удачной социализации!

воскресенье, 8 мая 2011 г.

SharePoint Solution Installer Rus

Также выкладываю аналогичный русификатор для оригинального установщика решений (под SharePoint 2007).

Скачивать тут.

Установка: Поместить содержимое архива в папку с инсталлятором.

суббота, 23 апреля 2011 г.

SharePoint 2010 Solution Installer

По просьбам устанавливающих сделал апгрейд установщика решений SharePoint под SharePoint 2010.
А также добавил русскую локализацию.

Скачать можно тут!
It can be downloaded here!

P.S. Не совместим с WSS 3.0 и MOSS 2007.
P.P.S. Об ошибках и неточностях перевода пишите в комментариях. Постараюсь всё учесть.
Автор обновления не претендует на авторство самого приложения.