TechEd Russia 2012

Я буду на TechEd Russia 2012 в зоне Community Experts  на стенде Microsoft Office. Зона Community Experts располагается в Зоне Общения на выставке, 4 этаж. Обязательно подходите познакомиться и пообщаться вживую, отвечу на все вопросы по SharePoint и стеку технологий Microsoft.



Как писать правильный код для SharePoint

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

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

Привожу текст письма с правилами “как есть”:

Господа, давайте сразу делать веб-части для главной НОРМАЛЬНО

1. Никаких visual web part, используйте sandboxed visual web part

2. Никаких ссылок на скрипты и css в разметке, используйте классы CssRegistratoin и ScriptLink

3. Получение списков только через web.GetList(SPUrlUtility.CombineUrls(web.Url, listRelativeUrl)

4. Списки для веб-частей на главной лежат в корневом сайте, доступ к которому только через SPContext.Current.Site.RootWeb

5. Никаких вызов конструкторов SPSite и site.OpenWeb крайней необходимости

6. В JS учитывайте что может быть много экземпляров веб-частей на странице, передавайте в скрипты id элементов с помощью control.ClientID

7. Так как веб-части на страницу могут быть добавлены после постбека – не используйте Page.IsPostBack для проверки первой загрузки

8. Лучший вариант – грузите данные в createchildcontrols

9. Используйте репитеры вместо склейки HTML в коде

10. Вставляйте везде SPMonitoredScope

11. Структурируйте код так, чтобы загрузка данных была отделена от генерации HTML (чтобы можно было кеширование прикрутить)

12. Отключайте по возможности ViewState

13. Обрабатывайте ошибки, чтобы при ошибке в веб-части не падала страница. Надо обрабатывать SPException, FileNotFoundException (сайт не найден, нет доступа), DirectoryNoFoundException (список не найден, нет доступа)

14. Если напишите try с пустым catch – оторву йайтса

15. Ошибки пишите в лог и выводите в красном Literal на страницу

16. Используйте только exception.ToString()

17. Корректно обрабатывайте случаи отсутствия элементов при выводе

18. На странице может быть две одинаковые веб-части и они должны корректно работать

Две ссылки по теме:

http://msdn.microsoft.com/en-us/library/bb985502(v=office.12).aspx

http://msdn.microsoft.com/en-us/library/dd583141(v=office.11).aspx

PS. Пункт 1 актуален для Visual Studio 2010, в 2012 такие веб-части создаются по-умолчанию.



5 правил логирования в SharePoint

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

Тема логирования очень любима многими разработчиками. Одни предпочитают писать свои велосипеды, другие пользуются готовыми фрейморками, третье используют возможности ОС.

Если вы разрабатываете решения для SharePoint, то вам необходимо придерживаться следующих правил:

0. Не используйте фреймворки

Даже если вы очень любите log4net, или NLog, или EventLog, или System.Diagnostics.Trace, или пишете свой велосипед, то никогда не используйте ничего из вышеперечисленного.

В SharePoint существует своя система логирования, называемая Unified Logging System (ULS). Если у вас возникает вопрос чем ULS лучше чем <подставьте сюда свой любимый фреймворк>, то вот основные причины:

  • ULS уже используется компонентами SharePoint, используя другую систему вам придется собирать логи в нескольких местах
  • ULS гибко настраивается из Central Administration и PowerShell
  • ULS умеет писать в Windows Event Log, не требуя при этом привилегий
  • ULS обеспечивает сжатие текстовых логов на диске
  • ULS не требует правки web.config (что очень важно для многосерверной фермы)
  • SharePoint умеет собирать логи ULS (и не только их) со многих серверов в одну базу
1.  В простых случаях не делайте ничего

SharePoint сделан так, что необработанные исключения внутри процессов SharePoint попадают в ULS.  В случае возникновения ошибки очень легко будет в ULS найти stack trace, а если включить уровень логированя VerboseEx, то и все запросы к базе со статистикой.

Для просмотра логов удобнее всего применять утилиту UlsViewer, для русской версии Windows Server может понадобиться патч.

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

2. Используйте SPMonitoredScope везде

Класс SPMonitoredScope очень прост в использовании:

using (new SPMonitoredScope("My Monitored Scope"))
{
    // Do Stuff...
}

В лог пишутся сообщение при входе в scope и при выходе из него, также записывается время выполнения scope. По умолчанию сообщения от SPMonitoredScope  имеют уровень Verbose.

С помощью SPMonitoredScope  также можно логировать и другие параметры быстродействия и потребления ресурсов

using (new SPMonitoredScope("My Scope Name",1000,
   new SPRequestUsageCounter(3),
   new SPSqlQueryCounter(10)))
{
    //Do Stuff...
}

Если внутри scope время выполнения превысит 1000мс, или количество объектов SPRequest (SPWeb и SPSite) превысит 3, или количество запросов к базе превысит 10, то уровень логирования повысится до High. Кроме того в лог попадут фактические значения этих параметров, а также места создания объектов SPSite\SPWeb в виде stack trace и места где происходили запросы к БД.

Но самое важное заключается в том, что SPMonitoredScope попадает в Developer Dashboard.

Если написать такой код:

using (new SPMonitoredScope("My Monitored Scope")) 
{                
    using (new SPMonitoredScope("My Sub-Monitored Scope")) 
    { 
        using (new SPMonitoredScope("My Sub-Sub-Monitored Scope")) 
        { 
        }

        using (new SPMonitoredScope("Another deep scope")) 
        { 
        } 
    } 
}
То в Developer Dashboard можно увидеть следующую картину:

image_4_204207CF

3. Используйте SPDiagnosticsService для записи в лог

Непосредственно в ULS можно писать с помощью класса SPDiagnosticsService.

Запись в Trace Log:

SPDiagnosticsService diagSvc = SPDiagnosticsService.Local; 
diagSvc.WriteTrace(0, 
    new SPDiagnosticsCategory("My Category", 
        TraceSeverity.Monitorable, 
        EventSeverity.Error), 
    TraceSeverity.Monitorable, 
    "An exception occurred: {0}", 
    new object[] {ex}); 

В ULS для каждой записи указывается Area и Category. При таком вызове Area будет равна Unknown.

Также можно писать сразу в Event log:

SPDiagnosticsService diagSvc = SPDiagnosticsService.Local; 
diagSvc.WriteEvent(0, 
        new SPDiagnosticsCategory("My Category", 
            TraceSeverity.Monitorable, 
            EventSeverity.Warning), 
        EventSeverity.Error, 
        "Exception occured {0}", new object[] {ex}); 
4. Наследуйтесь от SPDiagnosticsServiceBase для гибкой настройки логирования

Если вы создаете большой компонент для SharePoint, то имеет смысл создать свой сервис логирования (наследник класса SPDiagnosticsServiceBase). В нем можно определить свои Area и Category, а также более легковесные методы для логирования. В Central Administration и PowerShell можно будет задать уровень логирования для каждой категории или Area.

public class LoggingService : SPDiagnosticsServiceBase
{
    public static string DiagnosticAreaName = "My";
    private static LoggingService _Current;
    public static LoggingService Current
    {
        get
        {
            if (_Current == null)
            {
                _Current = new LoggingService();
            }
 
            return _Current;
        }
    }
 
    private LoggingService()
        : base("My Logging Service", SPFarm.Local)
    {
 
    }
 
    protected override IEnumerable<SPDiagnosticsArea> ProvideAreas()
    {
        List<SPDiagnosticsArea> areas = new List<SPDiagnosticsArea>
        {
            new SPDiagnosticsArea(DiagnosticAreaName, new List<SPDiagnosticsCategory>
            {
                new SPDiagnosticsCategory("WebParts", TraceSeverity.Unexpected, EventSeverity.Error)
            })
        };
 
        return areas;
    }
 
    public static void LogError(string categoryName, string errorMessage)
    {
        SPDiagnosticsCategory category = LoggingService.Current.Areas[DiagnosticAreaName].Categories[categoryName];
        LoggingService.Current.WriteTrace(0, category, TraceSeverity.Unexpected, errorMessage);
    }
}

Дальше просто:

LoggingService.LogError("WebParts", ex.ToString);
5. Используйте сервис диагностики для клиентских приложений

В SharePoint есть веб-сервис /_vti_bin/diagnostics.asmx. Он содержит всего один метод, который пишет данные в ULS в категорию SharePoint Foundation –> Unified Logging Service  с уровнем Verbose.

Если вы создаете приложение на Silverlight или Javascript, то другим образом довольно сложно обеспечить логирование, доступное разработчику и администратору.

В библиотеках javascript, предоставляемых SharePoint, есть функции
ULSOnError(msg, url, line) и ULSSendException(ex). Но просто вызвать их не получится. Перед каждым вызовом функции необходимо присвоить ULS.enable значение true.

ULS.enable = true;
ULSOnError("Hello trace", document.location.href, 0);

 

PS. Не забывайте что ULS создан для разработчиков и администраторов. Для пользователей иногда тоже надо хранить и показывать некоторый журнал того что происходило. В этом случае лучше всего работают списки.

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



SharePoint 2013 для разработчиков

Недавно в открытом доступе появилась preview версия SharePoint и Ofiice 2013. Про возможности для бизнеса и конечных пользователей напишут еще не раз, гораздо интереснее как будет выглядеть разработка под новую версию платформы.

1. Javascript

Если вы еще не знаете Javascript, то бросайте все и срочно изучайте.

В новой версии javascript будет использоваться для:

  1. Рендеринга представлений и форм списка
  2. Рендеринга результатов поиска
  3. Создания приложений Office и SharePoint
  4. Большинства кастомизаций интерфейса

Большая часть кода для SharePoint и Office 2013 будет написана на JS. И почти никакого xsl.

2. Поиск

В SharePoint 2013 поиск стал основным инструментом для доступа к данным. С помощью поиска можно обратиться к любым данным, которые есть в SharePoint. Даже в 2010 версии поиск был очень мощным инструментом, позволяющим работать с большими объемами данных и сложными структурами сайтов. В новой версии поиск дополнился многими возможностями. Если вы еще не знакомы с поиском SharePoint, то стоит это исправить. Возможно и для версии SharePoint 2010 найдете много полезных применений поиска в решениях.

Особенно важно что в версии 2013 поиск может выдавать результаты почти в реальном времени.

3. Social

Если раньше SharePoint ассоциировался со словом collaboration (совместная работа), то с версии 2013 он будет ассоциироваться со словом social (социальный). Лента сообщений, шаринг, фолловинг, комментирование, лайки, сообщества, рейтинги, бейджи – теперь это не просто есть в SharePoint (оно и версии 2010 было), теперь это основной инструмент взаимодействия.

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

4. Workflow Foundation 4

Кто не в курсе – WF4 написан с нуля и не имеет почти ничего общего с предыдущей версией. В SharePoint 2013 есть поддержка новых рабочих процессов, работающих на движке Workflow Foundation 4.

В отличие от предыдущих версий в WF4:

  1. Процессы декларативны, задаются в XML, даже если создавать процессы в Visual Studio.
  2. Процессы в WF4 полны по Тьюрингу, то есть могут описать любой алгоритм.
  3. Процессы, созданные в SharePoint Designer 2013 могут иметь циклы и переходы к предыдущим состояниям.
  4. Процессы могут общаться с внешним миром посредством HTTP запросов. Так как SharePoint 2013, наряду с клиентской объектной моделью, предоставляет REST интерфейс, то с помощью HTTP запросов можно сделать (почти) все.
  5. Фактически нельзя использовать .NET код для Workflows.

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

WF4 в SharePoint 2013 стал middleware для решений.

5. Cloud

Облака повсюду. В SharePoint 2013 самые большие вложения сделаны именно в развитие облачных решений. Это не могло не повлиять на архитектуру.

В основе новой архитектуры лежит идея, что любой кастом должен выполняться не на машинах фермы SharePoint. Например упомянутый выше WF4 фактически выполняется в отдельном сервисе (Windows Azure Workflow), сервис общается с SharePoint  с помощью клиентской объектной модели.

Новая модель приложений (apps) для SharePoint требует соответствия такой архитектуре и вообще  не позволяет выполнять код на сервере SharePoint.

Это все означает что придется много использовать HTTP, а основным инструментом отладки станет Fiddler.

6. Новый дизайн и темы

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

Для порталов публикации облегчили процесс создания нового дизайна. Теперь верстальщикам гораздо меньше потребуется знать SharePoint чтобы сделать на нем сайт.

7. Claims аутентификация и OAuth

В SharePoint 2013 основной вид аутентификации – claims. Кто еще не знаком с ней, то надо срочно исправить этот пробел. Claims аутентификация в SharePoint таит некоторые подводные камни и, к сожалению, не любой код, работающий в режиме classic будет корректно работать в режиме claims.

Также появилась возможность аутентификации по протоколу OAuth. Вам обязательно придется использовать OAuth для приложений.

Что почти не изменилось

1. Серверная объектная модель

WSP пакеты, фичи, CAML и глюки парсера, unmanaged код под капотом, списки и библиотеки – все это осталось. Некоторые новые возможности появились, но незначительно. Это все работает, поддерживается (в on-premise и sandbox) и может быть применено в решениях.

Несмотря на то что SharePoint 2013 собран под .NET 4, я не нашел что в объектной модели используется из новой версии фреймворка.

2. Внутренняя архитектура

Все также есть Service Applications. Появилось несколько новых типов сервис-приложений, но больших изменений нет.

Заключение

Большая часть изменения новой версии направлена на Office 356. Некоторые приложения будут работать в Office365 и не будут в on-premise варианте.  С другой стороны российские реалии говорят о том, что компании неохотно размещают свои данные в облаках.

Поэтому основной фокус в ближайшее время останется на разработке решений для on-premise. А новая модель приложений с marketplace в этому случае будет востребована гораздо слабее, чем хотелось бы Microsoft.

Более подробно об этом в следующий раз.



Парси строки правильно или как поломали Windows Azure Workflow

Решил я на ночь глядя поиграться в новым Workflow для SharePoint 2013. Для этого надо поставить Workflow Service (WAW).  Приключения мои начались с того что по ссылке инструкция не правильная. По умолчанию на порту 12290 поднимается HTTPS эндпоинт, в а документации указана команда где используется http.

С этим я быстро разобрался, благо не первый день знаком с SharePoint и его особенностями. Но все равно достучаться до сервиса не получается, отдается ошибка.  Event log написано что не удается распарсить значение конфигурационного параметра которое сейчас 0.1.

Покопавшись в конфигах я обнаружил что нужное значение в базе WFResourceManagementDB в таблице WorkflowServiceConfig, там действительно записано “0.1” в поле типа nvarchar(max).

А причина ошибки банальна. У меня русская версия Windows Server и системный разделитель дробной части стоит запятая, а не точка.

Код внутри сервиса парсит строку вызывая Single.Parse(value) и падает на “неверном” разделителе. Из этого мораль: всегда парси (и записывай) конфигурационные параметры с указанием культуры, лучше инвариантной.

Ниже описание ошибки из event log, чтобы этот пост по тексту находился Улыбка

The Workflow Service Backend failed to start at location 'WorkflowServiceBackendHost.OnServiceStarted' due to an exception: System.IO.InvalidDataException: Workflow Service configuration 'WorkflowServiceMaxDispatcherFailureRate' is not formatted correctly. The configuration string should be parsable to a 'Single' type. Current config value is '0.1'.

PS. Использование типа Single намекает на то, что WAW написан на VB.NET.