понедельник, 4 марта 2013 г.

Создание Timer Jobs в SharePoint 2010 ориентированных на конкретный Web-Applications

Обзор Timer Jobs в SharePoint 2010

Microsoft SharePoint 2010 timer jobs выполняют большую часть фоновых работ, которые необходимы для поддержания вашей фермы SharePoint. Они могут быть настроены работать только один раз, или на постоянной графику. SharePoint используют timer jobs для поддержания длительных рабочих процессов, например чтобы очистить старые сайты и журналы, а также для мониторинга проблем фермы. SharePoint также использует timer jobs для выполнения логики развертывания решения и функцию активации. Timer jobs имеют ряд преимуществ. Они могут работать периодически и независимо от пользователей, которые имеют доступ к вашим сайтам SharePoint.
Вы можете просмотреть задания таймера на ферме с помощью страницы Job Definitions  в SharePoint 2010 Central Administration. Чтобы получить доступ к странице Job Definitions, выберите All Programs > Microsoft SharePoint 2010 Products > SharePoint 2010 Central Administration. На сайте центра администрирования выберите Monitoring ссылке. Наконец, нажмите ссылку Review Job Definitions в разделе Timer Jobs части страницы (рисунке 1).

Рисунок 1.  

Подготовка к созданию timer jobs SharePoint

Прежде чем вы сможете создать свой SharePoint timer jobs, необходимо установить Microsoft Visual Studio 2010. SharePoint 2010 должен быть установлен ​​на компьютере разработчика.
После установки необходимого программного обеспечения, запускаем студию и создаем новый проект SharePoint Empty Project, выбрав File > New > Project. (рисунок 2). В диалоговом окне проверьте, что NET Framework 3.5 выбран в раскрывающемся списке в верхней части, а затем нажмите кнопку ОК. 

Рисунок 2.












Сразу после нажатия кнопки ОК появится диалоговое окно, как показано на рисунке 3. Введите URL вашего сайта SharePoint в текстовое поле, выберите Deploy as a farm, а затем нажмите кнопку Готово. 

Рисунок 3.














После нажатия кнопки Готово Visual Studio создает и откроет проект, как показано на рисунке 4. Теперь, когда проект создан, вы можете начать добавлять классы, которые необходимы, чтобы сформировать основу вашей работы таймера SharePoint.

Рисунок 4.













Создание рaботы Timer jobs Sharepoint

Все задания таймера, в том числе те, которые установлены с SharePoint, создаются и выполняются с помощью SPJobDefinition класса. Для создания нового таймера SharePoint работу, необходимо сначала добавить в проект класс, который наследует от SPJobDefinition класса. В следующем фрагменте кода показан пример класса, который наследует от SPJobDefinition класса.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint;

namespace ArchiveFilesJob {
    public class ArchiveJob : SPJobDefinition {

        public ArchiveJob() : base() { }

        public ArchiveJob(string jobName, SPWebApplication webApp)
            : base(jobName, webApp, null, SPJobLockType.Job) {
            this.Title = jobName;
        }

        public override void Execute(Guid targetInstanceId) {
            // Put your job's code here.
        }
    }
}

Во фрагменте кода, ArchiveJob класс наследуется от SPJobDefinition класса. Когда вы создаете свой конструктор, вы должны передать значения для четырех параметров, описанных ниже в конструктор базового класса.


Имя Название работы.
WebApplication Экземпляр SPWebApplication класса, которому принадлежит эта работа.
Сервер Экземпляр класса SPServer, связанных с этой работой. Передайте ноль, если эта работа не связана с конкретным сервером.
LockType SPJobLockType значение, которое указывает на обстоятельства, при которых несколько экземпляров задания могут быть запущены одновременно.
 
В предыдущем фрагменте кода, null передается в качестве значения для сервера, поскольку эта работа не связана с конкретным сервером. SPJobLockType.Job передается в качестве значения для LockType, чтобы предотвратить SharePoint от запуска нескольких экземпляров работу одновременно. В таблице 2 перечислены возможные значения SPJobLockType и их описания.


None Блокировка отключается. Работа выполняется на всех серверах фермы, независимо от параметра который вы передаете для SPServer объекта.
ContentDatabase Работа выполняется для каждой базы данных контента, связанного с веб-приложением.
Job Только один сервер может выполнить задание за один раз.

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

Включение конфигурации для timer jobs  SharePoint

Для хранения данных конфигурации работы, необходимо создать классы, которые будут  содержать эту конфигурацию и хранить его в SharePoint. Во-первых, этот класс должен наследовать от класса SPPersistedObject. Далее, поля в классе должы быть открытыми, отмеченными [Persisted] атрибутом, а также встроенного типа данных (например, Guid, Int, String, и так далее), наследуется от SPAutoSerializingObject, или должен представляет собой коллекцию типа, который содержит одну из встроенных типов или тип наследования от SPAutoSerializingObject. Только поля сохраняются, а не свойства. Следующий фрагмент кода показывает два класса, которые используются для настройки ArchiveJob класса.

using Microsoft.SharePoint.Administration;
public class ArchiveJobSettings : SPPersistedObject {
    public static string SettingsName = "ArchiveFilesJobSettings";

    public ArchiveJobSettings() { }
    public ArchiveJobSettings(SPPersistedObject parent, Guid id)
        : base(SettingsName, parent, id) { }

    [Persisted]
    public Dictionary<Guid, SiteArchiveSettings> SiteArchiveSettings =
        new Dictionary<Guid, SiteArchiveSettings>();
}

public class SiteArchiveSettings : SPAutoSerializingObject {
    [Persisted]
    public Guid SiteCollectionId = Guid.Empty;
    [Persisted]
    public Guid SiteId = Guid.Empty;
    [Persisted]
    public Guid SourceDocLibId = Guid.Empty;
    [Persisted]
    public Guid DestinationDocLibId = Guid.Empty;
    [Persisted]
    public int MaxDays = 30;
    [Persisted]
    public bool Enabled = true;
Во фрагменте кода, класс ArchiveJobSettings используется для настройки ArchiveJob класса. Он наследует от SPPersistedObject, и имеет одно поле с именем SiteArchiveSettings, помеченный [Persisted] атрибутом. Поле SiteArchiveSettings позволяет выполнение заданий на любом количестве сайтов в том же веб приложении. Тип данных поля SiteArchiveSettings является коллекцией SiteArchiveSettings объектов, наследуемых  от класса SPAutoSerializingObject.
Следует отметить, что класс ArchiveJobSettings имеет два конструктора - конструктор по умолчанию, который является обязательным для всех классов сериализации, и второй конструктор, который вызывает конструктор своего базового класса. Второй конструктор передает экземпляр SPPersistedObject, который действует как родительский объект ArchiveJobSettings, и Guid, который используется, чтобы назначить ему уникальный идентификатор в SharePoint. Поскольку ArchiveJob связан с конкретным объектом SPWebApplication то тот же объект SPWebApplication становится родителем объекта ArchiveJobSettings, когда он сохраняется в SharePoint.
Класс SiteArchiveSettings содержит сайт-специфические настройки для ArchiveJob класса. Он наследует от SPAutoSerializingObject, и его поля придерживаются тех же правил, как и для класса SPPersistedObject. Поля, отмеченные [Persisted] атрибутом позволяет им сохраняться в  SharePoint.

ArchiveJobSettings jobSettings =
    new ArchiveJobSettings(webApplication, Guid.NewGuid());
// Be sure to change the URL below to one appropriate for your
// environment.
using (SPSite siteCollection = new SPSite("http://local.demo.com")) {
    using (SPWeb site = siteCollection.RootWeb) {
        SiteArchiveSettings siteSettings = new SiteArchiveSettings();
        siteSettings.SiteCollectionId = site.Site.ID;
        siteSettings.SiteId = site.ID;
        siteSettings.SourceDocLibId = site.Lists["MyDocLib"].ID;
        siteSettings.DestinationDocLibId =
            site.Lists["MyDocLibArchive"].ID;
        siteSettings.MaxDays = 30;
        siteSettings.Enabled = true;
        jobSettings.SiteArchiveSettings.Add(site.ID, siteSettings);
    }
}
jobSettings.Update(true);

Во фрагменте кода, вы создаете конфигурацию ArchiveJobSettings класса, передавая экземпляр SPWebApplication, который представляет собой объект веб-приложения SharePoint и новый Guid. После этого, можно настроить поля в классе.
Для получения конфигурации, необходимо получить экземпляр SPWebApplication, вызвать его метод GetChild, а затем передать в него класс, который у вас служит хранилищем конфигурации.
public override void Execute(Guid targetInstanceId) {
    ArchiveJobSettings jobSettings =
        this.WebApplication.GetChild<ArchiveJobSettings>(ArchiveJobSettings.SettingsName);
    if (jobSettings == null) {
        return;
    }
    // Code omitted.
}

Класс ArchiveJobSettings был извлечен из SharePoint, вызвав GetChild метод родителя SPWebApplication. Если ничего не было ранее сохранено в SharePoint, вызов GetChild метод возвращает нулевое значение. 

Развертывание задания таймера

Теперь, когда вы создали задание и конфигурации классов, вы должны добавить функцию установки решения в SharePoint сервере 

Рисунок 5
 












Добавляем новую фичу, конфигурируем её при необходимости. Добавляем обработчик для включиения и выключения фичи. Для этого в контекстном меню фичи выбираем пункт Add Event Receiver. После этого, в сгенерированном коде вы должны раскомментировать FeatureActivated и FeatureDeactivating методы. Остальные можно удалить, потому что они не используются. Далее, добавляем код в FeatureActivated метод для создания таймера и код в FeatureDeactivating метод, чтобы удалить его соответственно. В следующем примере показано, как зарегистрировать и отменить регистрацию ArchiveFilesJob объекта.

public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
    SPWebApplication webApplication = (SPWebApplication)properties.Feature.Parent;

    // Remove job if it exists.
    DeleteJobAndSettings(webApplication);

    // Create the job.
    ArchiveJob job = new ArchiveJob(ArchiveJob.JobName, webApplication);

    // Create the schedule so that the job runs daily, sometime between midnight and 4 A.M.
    SPDailySchedule schedule = new SPDailySchedule();
    schedule.BeginHour = 0;
    schedule.BeginMinute = 0;
    schedule.BeginSecond = 0;
    schedule.EndHour = 3;
    schedule.EndMinute = 59;
    schedule.EndSecond = 59;
    job.Schedule = schedule;
    job.Update();

    // Configure the job to archive files in a few sites in this web
    // application.
    ArchiveJobSettings jobSettings = new ArchiveJobSettings(webApplication, Guid.NewGuid());
    using (SPSite siteCollection = new SPSite("http://local.demo.com"))
    {
        SPWeb site = siteCollection.RootWeb;
        SiteArchiveSettings siteSettings = new SiteArchiveSettings();
        siteSettings.SiteCollectionId = site.Site.ID;
        siteSettings.SiteId = site.ID;
        siteSettings.SourceDocLibId = site.Lists["MyDocLib"].ID;
        siteSettings.DestinationDocLibId = site.Lists["MyDocLibArchive"].ID;
        siteSettings.MaxDays = 30;
        siteSettings.Enabled = true;
        jobSettings.SiteArchiveSettings.Add(site.ID, siteSettings);
        // Add more sites here.
    }
    jobSettings.Update(true);
}

public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
{
    SPWebApplication webApplication =  (SPWebApplication)properties.Feature.Parent;
    DeleteJobAndSettings(webApplication);
}

private void DeleteJobAndSettings(SPWebApplication webApplication)
{
    foreach (SPJobDefinition job in webApplication.JobDefinitions) {
        if (job.Name == ArchiveJob.JobName)
        {
            job.Delete();
            break;
        }
    }

    // Delete the job's settings.
    ArchiveJobSettings jobSettings =
        webApplication.GetChild<ArchiveJobSettings>(ArchiveJobSettings.SettingsName);
    if (jobSettings != null)
        jobSettings.Delete();


В примере кода, FeatureActivated метод получает экземпляр SPWebApplication класса (для которых эта функция активируется). Далее, FeatureActivated метод вызывает метод DeleteJobAndSettings, чтобы удалить существующие таймеры и настройки, если они уже существуют. Далее создайм таймер. После того, настраиваем собственное расписание запуска.

SPMinuteSchedule Выполнение задания каждую минуту.
SPHourlySchedule Выполнение задания каждый час.
SPDailySchedule Выполнение задания в день.
SPWeeklySchedule Выполнение задания в неделю.
SPMonthlySchedule Выполнение задания в месяц.
SPYearlySchedule Выполнение задания в год. 

В предыдущем примере кода, SPDailySchedule класса используется для выполнения задания в день. Указываются значения самого раннего и самого позднего времени, соответственно. Таймер служба случайным образом выбирает время, в течение этого интервала, чтобы начать работу. После того как вы установите расписание для свого таймера, необходимо вызвать обновление метода таймера. Последним шагом в методе для создания экземпляра класса ArchiveJobSettings, установливаем его свойства, а затем сохраняем.
В FeatureDeactivating методе, метод DeleteJobAndSettings вызывается, чтобы удалить ранее зарегистрированные таймеры. Метод использует DeleteJobAndSetting.

Тестирование и отладка ваших SharePoint timer jobs

При отладке кода SharePoint, устанавливается Debug режим, а затем нажмите F5 для отладки проекта. Visual Studio компилирует код, в пакете SharePoint решения (WSP-файл), а затем развертывает пакет решений в SharePoint сервере.

Для отладки задания таймера

Для отладки таймера в SharePoint, необходимо подключить к процессу, выберите Debug > Attach to proccess в строке меню Visual Studio.
В открывшемся окне проверяем, что флажки в нижней части выбраны, а затем выберираем OWSTIMER.EXE из списка доступных процессов.
Рисунок 6











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

четверг, 3 января 2013 г.

SQL Server 2008 R2. Интеграция Reporting Services и SharePoint 2010 шаг за шагом

Не секрет, что продукт фирмы Microsoft SharePoint – это один из самых динамически быстро развивающихся продуктов. В SQL Server 2008 R2 появилась долгожданная возможность интеграции Reporting Services и SharePoint 2010. Если вдуматься, это вполне логичный шаг. В обоих этих продуктах используются одни и те же технологии, так почему же не скрестить их и попробовать, что из этого получиться? В данной статье остановлюсь на процессе инсталляции Reporting Services входящий в SQL Server 2008 R2 в режиме интеграции с SharePoint 2010, и какие новые возможности предоставляются администратору баз данных.
В предыдущих версиях Reporting Services требовалось скачать дополнительный компонент для интеграции с SharePoint 2010, на сегодняшний день инсталляция этого компонента производиться автоматически. Давайте посмотрим шаг за шагом процесс установки Reporting Services в режиме интеграции с SharePoint 2010. Статья навеяна по мотивам практически исполняемой задачей интеграции этих двух продуктов. При разборе технической документации выяснилось, что написано достаточно много, но чтобы выстроить четкий план решения практической задачи интеграции Reporting Services SQL Server 2008 R2 и SharePoint 2010 – на это уходит достаточно много времени. Итак, приступим.
Посмотрим на демонстрационное окружение:

Имя компьютера
Операционная система
Службы и приложения
DC
Windows Server 2008 R2
Доменная служба Active Directory (test.local), DNS
SPS
Windows Server 2008 R2
SharePoint 2010, Microsoft SQL Server 2008 R2
Это могут быть физические серверы, могут быть виртуальные под Hyper-V. С точки зрения безопасности лучше, чтобы домен контроллер был всегда выделенным без установленного лишнего программного обеспечения. Все программные продукты русской редакции, надо отметить, что фирма Microsoft серьезно потрудилась над переводом своих продуктов.
Конечно же, для установки нам понадобиться дистрибутивы SQL Server 2008 R2 и SharePoint 2010. На первом этапе – предположим у вас уже есть установленный SharePoint 2010 на сервере SPS, начнем интеграцию с него.
1. Вставляем дистрибутив SharePoint 2010. Если автозапуск не стартовал, с компакт диска запускаем файл splash.hta. В разделе «Установить» выбираем пункт «Установить необходимое ПО». Здесь нужен компонент «Настройка служб отчетов SQL Server 2008R2». Выбираем «Далее». 
Рисунок 1. Начало установки средств интеграции.
2. Соглашаемся с лицензионным соглашением, перед этим внимательно и обстоятельно его читаем. Выбираем «Далее».
3. На этом этапе программа установки SharePoint 2010 автоматически скачивает необходимые компоненты из Интернет и конфигурирует сервер. Дожидаемся окончания установки. Выбираем «Готово».
Надо отметить, что интеграция возможна только в том случае, если программный продукт SharePoint 2010 установлен в режиме фермы. В том случае, если служба Reporting Services и сервер фермы SharePoint находятся на разных серверах, нужно произвести минимальную установку SharePoint 2010 с присоединением сервера к существующей ферме, а затем переходить к следующему этапу.
На втором этапе настроим сервер SPS, на котором уже установлен экземпляр по умолчанию SQL Server 2008 R2. Для этой цели нам понадобиться дистрибутив SQL Server 2008 R2.
1. Вставляем дистрибутив SQL Server 2008 R2. Если автозапуск не стартовал, с компакт диска запускаем файл setup.exe. Выбираем справа «Установка» – «Новая установка или добавление компонентов к существующей установке».
2. На странице «Правила поддержки установки» нажимаем «ОК». Если кнопка не доступна для нажатия нужно выбрать кнопку «Показать подробности» и посмотреть ошибки.
3. На странице «Файлы поддержки программы установки» нажимаем «Установить».
4. На странице «Правила поддержки установки» нажимаем «Далее». Если кнопка не доступна для нажатия нужно нажать «Показать подробности» и посмотреть ошибки.
5. На странице «Тип установки» выбираем «Добавление компонентов к существующему экземпляру SQL Server R2». Нажимаем «Далее».
 Рисунок 3. Выбор типа установки.
6. На странице «Выбор компонентов» отмечаем «Службы Reporting Services». Нажимаем «Далее» 3 раза.
7. На странице «Конфигурация сервера» вводим доменную учетную запись, от имени которой будет запускаться служба Reporting Services. Нажимаем «Далее».
8. На странице «Настройка служб Reporting Services» выбираем «Установить конфигурацию по умолчанию для работы в режиме интеграции с SharePoint». Нажимаем «Далее» 3 раза и затем «Установить».
9. На странице «Готово» можно убедиться, что служба Reporting Services успешно установлена и нажать «Готово».
Как видите все достаточно просто, в случае если и SharePoint 2010 и SQL Server 2008 R2 находится на одном сервере.
Если на шаге 8 (страница «Настройка служб Reporting Services») выбрано «Установить, но не настраивать сервер отчетов» то службу Reporting Services необходимо будет настроить через инструмент «Диспетчер конфигурации служб Reporting Services»:
1. Нажимаем последовательно «Пуск» – «Все программы» – «Microsoft SQL Server R2» – «Средства настройки» – «Диспетчер конфигурации служб Reporting Services» – «MSSQLServer»
2. Если сервис остановлен, то на странице «SPS\MSSQLServer» нажимаем «Запуск»
Рисунок 4. Стартовая страница диспетчера конфигурации
3. На странице «Учетная запись службы» выбираем «Использовать другую учетную запись» – вводим доменную учетную запись и пароль, нажимаем «Применить».

Рисунок 5. Страница выбора учетной записи службы.
4. На странице «URL-адрес веб-службы» можно оставить все значения по умолчанию, нажимаем «Применить».
5. На странице «База данных» настроим базу данных для режима интеграции с SharePoint:
a) Нажимаем «Изменить базу данных».
b) Выбираем «Создать новую базу данных сервера отчетов», нажимаем «Далее».
c) На странице «Сервер базы данных» набираем имя экземпляра сервера SQL (в данном случае SPS) и учетную запись обладающая административными привилегиями создания базы данных, нажимаем «Далее».
d) На странице «База данных» набираем имя базы данных, к примеру «ReportServer», и выбираем «Режим интеграции с SharePoint», нажимаем «Далее».

Рисунок 6. Выбор базы данных.
e) На странице «Учетные данные» можно выбрать учетные данные, отличные от данных текущего пользователя. От имени выбранной учетной записи SQL Server будет подключаться к базе данных сервера отчетов. По умолчанию выбирается учетная запись службы. Нажимаем «Далее»
f) На странице «Сводка» еще раз просматриваем все выбранные установки и жмем «Установить».
g) Нажимаем «Готово»
После окончания создания новой базы данных в режиме интеграции с SharePoint, нажимаем «Применить».
6. На странице «URL-адрес диспетчера отчетов» нужно указать виртуальный каталог. Можно оставить название по умолчанию «Reports». Нужно заметить, что напрямую к этому каталогу из браузера обратиться в режиме интеграции с SharePoint будет невозможно. Отчеты можно будет просматривать непосредственно с сервера SPS. Не забываем нажать «Применить». 

Рисунок 7 URL-адрес диспетчера отчетов.
7. На следующем шаге чтобы убедиться, что все настроено правильно, нужно закрыть и снова открыть «Диспетчер конфигурации служб Reporting Services». Переходим на страницу «Масштабное развертывание». Проверим что «Режим сервера отчетов» действительно «Интеграция с SharePoint» и статус состояния «Соединенный».

Рисунок 8. Проверка настройки Reporting Services.
Настройка Reporting Services успешно завершена. Как уже упоминалось ранее, управлять отчетами Reporting Services SQL Server 2008 R2 в режиме интеграции с SharePoint можно только из инструмента «Центр администрирования». На третьем этапе, перед тем как начать управление нужно произвести следующие настройки на сервере SPS:
1. Открываем «Центр администрирования» – «Пуск» – «Все программы» – «Microsoft SharePoint 2010 Products» – «Центр администрирования SharePoint 2010».
2. Переходим «Общие параметры приложения» – «Службы Reporting Services» – выбираем ссылку «Интеграция со службами Reporting Services»

Рисунок 9. Инструмент «Центр администрирования SharePoint 2010».
3. Вводим необходимую информацию:
- URL-адрес веб-службы сервера отчетов – http://sps/ReportServer
- Режим проверки подлинности – проверка подлинности Windows
- Имя пользователя – пользователь домена, обладающий административными привилегиями в ферме SharePoint 2010.
Нажимаем «ОК»

Рисунок 10. Страница «Интеграция со службами Reporting Services».
4. В случае успешного ввода необходимой информации, процесс интеграции успешно завершается. Выбираем «Закрыть»
Рисунок 11. Сводка информации по интеграции со службами Reporting Services.
На последнем этапе остается задача создание отчетов прямо из необходимых библиотек. Здесь есть два подхода. Первый подход это создать узел SharePoint 2010 с использованием шаблона «BI Center». Этот подход не требует дополнительных усилий, на уровне библиотеки на таком узле уже доступны необходимые типы контента при создании нового документа. На втором подходе давайте остановимся поподробней, так как чаще всего встречается именно такая практическая задача. Подход заключается в том, чтобы в существующей библиотеке добавить, например новый тип контента, позволяющий создавать отчет Reporting Services. Итак, по шагам:
1. Открываем необходимый узел SharePoint, например http://sps.
2. Переходим в библиотеку «Общие документы» на ленте выбираем – «Библиотека» – «Параметры» – «Параметры библиотеки» (Если на ленте нет меню «Параметры» значит, пользователь под которым вы зашли не обладает необходимыми административными привилегиями). 
Рисунок 12. Навигация на ленте библиотеки SharePoint.
3. В разделе «Общие параметры» переходим по ссылке «Дополнительные параметры» – В разделе «Типы контента» устанавливаем «Да». Тем самым мы разрешаем управление типами контента для текущей библиотеки. Выбираем внизу экрана «ОК»

Рисунок 13. Включение выбора типа контента на уровне библиотеки.
4. На странице «Библиотека документов» в разделе «Типы контента» переходим по ссылке «Добавление из существующих типов контента». В выпадающем списке выбираем «Типы содержимого сервера отчетов». Есть три типа – «Источник данных отчета», «Модель в построителях отчетов» и Отчет в построителях отчетов. Выбираем необходимые кнопкой «Добавить». Нажимаем «Ок». 

Рисунок 14. Выбор нужного типа контента на уровне библиотеки.
Давайте проверим правильность произведенных настроек. На уровне библиотеки «Общие документы» на ленте выбираем «Документы» – «Создать документ». На ряду со стандартными типами контента, появилось три новых элемента «Источник данных контента», «Модель в построителе отчетов» и «Отчет в построителе отчетов».

Рисунок 15. Создание нового отчета как документа библиотеки.
Как можно убедиться, настройки прошли успешно теперь на уровне библиотеки «Общие документы» можно создать, к примеру, отчеты в Reporting Services. Нужно отметить, что построитель отчетов Report Builder 3.0 уже присутствует в системе и его устанавливать отдельно нет необходимости. Данная статья не охватывает работу с этим инструментом, полагаю, этот материал больше подойдет для отельной следующей статьи.
Очевидно, что жизнь администраторов баз данных, которые занимаются построением отчетов с помощью Reporting Services, значительно облегчается с выходом Microsoft SQL Server 2008 R2, за счет унификации интерфейса и полной интеграции с продуктом Microsoft SharePoint 2010.

среда, 19 декабря 2012 г.

Получение коллекция хранимых свойств в SPWeb

Некоторые вещи в рабочем проекте хранятся именно в SPWeb.Properties, и довольно часто возникает необходимость быстро посмотреть, что сейчас там лежит. Иногда - изменить какое-нибудь значение. Для этого я использую Power Shell. Набираем:
$s = Get-SPSite http://имя сайта
$w = $s.OpenWeb()
$w.Properties
А можно ещё так
Get-SPWeb -Identity http://server | Select -ExpandProperty AllProperties
Или еще проще
(Get-SPWeb -Identity http://server).Properties
А для изменения свойства используем:
$web = Get-SPWeb "http://SITE_URL"
$web.SetProperty("property_name", "property_value"); 

$web.Update(); 
Restart-Service W3SVC -force

Взято  из: http://omlin.blogspot.com/2011/01/spweb.html

пятница, 14 декабря 2012 г.

Работа с XML в SharePoint из Javascript

SharePoint очень тесно связан с XML. Все эти схемы полей и списков, определения элементов Ribbon, SharePoint Batch API, запросы SPQuery/CamlQuery - и многое другое. И если на стороне сервера всё более-менее понятно, там есть XmlReader/XmlWriter, XmlSerializer, XDocument и т.д., то что делать на стороне клиента? Как обрабатывать XML, формировать или изменять его, и какие для этого есть функции в SharePoint EcmaScript  - всю эту информацию я постарался собрать в сегодняшней статье.

XmlWriter

Впрочем, XmlWriter в SharePoint всё-таки есть. Располагается он в пространстве имен SP (т.е. SP.XmlWriter), а физически - находится в SP.Core.js. Применение в целом аналогично серверной версии, но поддерживаются только следующие методы:
  • create(stringBuilder)
  • writeStartElement(tagName)
  • writeElementString(tagName, value)
  • writeEndElement()
  • writeAttributeString(localname, value)
  • writeStartAttribute(localname)
  • writeEndAttribute()
  • writeString(value)
  • writeRaw(xml)
Впрочем, всё основное тут есть, так что можно смело использовать: в случае формирования XML в цикле или по каким-то сложным правилам, код станет гораздо более читаемым, по сравнению с формированием XML в строках. Простейший пример использования:

var camlQuery = new SP.CamlQuery();
var sb = new Sys.StringBuilder();
var writer = SP.XmlWriter.create(sb);
writer.writeStartElement("Where");
writer.writeStartElement("Eq");
writer.writeStartElement("FieldRef");
writer.writeAttributeString("Name""StatusID");
writer.writeEndElement();
writer.writeStartElement("Value");
writer.writeAttributeString("Type""Integer");
writer.writeString("1");
writer.writeEndElement();
writer.writeEndElement();
writer.writeEndElement();
writer.close();
camlQuery.set_viewXml(sb.toString());
//Result: <Where><Eq><FieldRef Name='StatusID' /><Value Type='Integer'>1</Value></Eq></Where>

Еще, при формировании XML может пригодиться вот этот метод:
SP.Utilities.HttpUtility.escapeXmlText, как не трудно догадаться из названия, этот метод эскейпит строку так, чтобы её потом можно было использовать в name или value xml-элементов и атрибутов.

Конвертируем объекты в XML

Конечно, XmlWriter это здорово, но даже на стороне сервера его редко кто использует, потому что есть гораздо более интересные варианты. Например, XmlSerializer. И если немного поискать, то действительно, в файле SP.Runtime.js можно обнаружить методы SP.DataConvert.writeDictionaryToXml и SP.DataConvert.writePropertiesToXml. И они действительно сериализуют js-объекты... Но, использовать их врядли получится. Дело в том, что эти методы всегда генерируют теги Property.

Например, вот такой код:
var sb = new Sys.StringBuilder();
var writer = SP.XmlWriter.create(sb);
var context = new SP.SerializationContext();
var dict = { hello: "world", complexObject: { property1: "value1", property2: "value2"} };
var fields = ["hello""complexObject"];
SP.DataConvert.writeDictionaryToXml(writer, dict, "root", fields, context);
// Значение сгенерированного XML можно теперь получить через sb.toString()? получим:
<root>
   <Property Name="hello" Type="String">world</Property>
   <Property Name="complexObject" Type="Dictionary">
        <Property Name="property1" Type="String">value1</Property>
        <Property Name="property2" Type="String">value2</Property>
   </Property> 
</root>
Parse XML

Для этого я использую jQuery, по моему мнению - это лучшее решение. Делается это очень просто:
var jQueryObjectFromXml = $(xmlString); 
и дальше уже делаем всё что угодно с полученным jQuery-объектом...
Впрочем, по умолчанию jQuery в SharePoint отсутствует, поэтому иногда может пригодиться и метод из SharePoint, который превращает XML в DOM-объект. Этот метод называется CUI.NativeUtility.createXMLDocFromString и расположен в файле CUI.js. Пример использования ниже:
var domElement = CUI.NativeUtility.createXMLDocFromString( 
'<root><child name="hello world"/><child>test value</child></root>');
domElement.firstChild.nodeName // "root"
domElement.firstChild.firstChild.attributes[0].value // "hello world"
domElement.firstChild.lastChild.text // "test value" 
Взято из: http://omlin.blogspot.ru/2011/07/xml-sharepoint-javascript.html 

Обзор 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, т.е. без панели быстрого запуска, частично без ленты, шапки и т.п. Часто используется в диалоговых окнах.

3. Filter=1 (http://site/lists/AllItems.aspx?Filter=1). Открытие представления списка с выпадающими фильтрами полей.


4. ToolPaneView=2 (http://site/defailt.aspx?ToolPaneView=2). Открытие страницы с панелью добавления веб-частей. В зависимости от значения параметра открывается различная вкладка: 2 – Обзор, 3 – Поиск, 5 – Импорт.

5. DisplayMode=Design (http://site/default.aspx?DisplayMode=Design). Открытие страницы в режиме редактирования.
6. Mobile=1 (http://site/default.aspx?Mobile=1). Отображение в виде для мобильных устройств.

Взято из: http://www.aviw.net/2012/09/get-sharepoint.html

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’
Пример.
Допустим имеем такой список:

Тестовое (консольное) приложение:
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;
        }
    }
}

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


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

Взято из: http://www.aviw.net/2012/12/caml.html

Разбиение запроса 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);
    }
}

Для моего списка результат выглядит следующим образом (консольное приложение):
Взято из: http://www.aviw.net/2012/08/spquery.html