понедельник, 18 апреля 2011 г.

Управление подсветкой синтаксиса в Sandcastle Help File Builder

На самом деле, лично я качественной подсветке синтаксиса всегда уделяю огромное внимание. Скажем, для этого блога, я потратил часов 5 (в течение нескольких дней), чтобы найти подходящую утилиту, которая бы подсвечивала код в точности также, как это делает Visual Studio.

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

Дак вот, именно поэтому довольно куцая подсветка кода в Sandcastle Help File Builder (далее SHFB), меня не слишком обрадовала (про Sandcastle я совсем недавно писал, это утилита для генерации документации в MSDN-стиле).

И вот, когда засел писать документацию в SHFB уже в третий раз (кстати, для SharePoint Fluent Ribbon), мне все-таки удалось эту проблему победить! Теперь моя документация выглядит всем на зависть и на заглядение:

И между прочим, сделать это совсем несложно. В этой статье я расскажу, как.

среда, 13 апреля 2011 г.

CodePlex про SharePoint

Иногда бывает довольно полезно полазать по CodePlex'у и открыть для себя пару маленьких проектов, которые делают большие вещи :)

SharePoint 2010 automatic sign-in with mixed authentication

Данный проект ничего на ваш сайт не добавляет, как это ни смешно. Зато - убирает лишнее! А именно, вот эту надоедливую страничку:
Если у вас локальный IP-шник, будете заходить на сайт сразу под Windows-аутентификацией. Иначе - Forms.

SharePoint 2010 Developer Dashboard Visualizer

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


Drag & Drop between SharePoint Document libraries

Если положить две библиотеки документов на одну страничку, можно перетаскивать между ними документы - Drag&Drop'ом! В некоторых случаях это может оказаться очень привлекательной фишкой.

SPContentLoader for SharePoint 2010

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

SharePoint Social Networking

Добавляет кнопки популярных социальных сетей и сервисов на ваш портал.



Первоначально, в этот обзор попало почти вдвое больше проектов, чем в итоге было опубликовано. К сожалению, низкое качество опенсурсных проектов - это довольно большая проблема. Иногда, вроде бы очень интересные идеи оказываются реализованы совершенно бестолково :(

Конечно, в таких случаях можно и нужно садиться, и писать самому. Но... не всегда хватает времени :(

понедельник, 11 апреля 2011 г.

Вопросы для собеседования по SharePoint Foundation 2010

Чтобы эффективно писать под SharePoint, нужно знать много всякой всячины. Причем, стандартный тест по ASP.Net тут как раз не поможет! Потому что нужно обязательно знать возможности и особенности платформы, чтобы не терять время на велосипедописание.

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

Несколько важных замечаний:
1. Ни на одном серьезном собеседовании по SharePoint я лично пока не присутствовал, так что никакого плагиата в этих вопросах нет, если совпадения есть, они случайны. Честно!
2. Вопросы не охватывают всю платформу, сосредотачиваясь на более общих знаниях. Написание вопросов - дело довольно долгое, поэтому вопросов по таким важным вещам, как BCS, WorkFlow, и некоторым другим очень важным темам (а также по SharePoint Server) - пока нет :) Возможно, напишу попозже.
3. Вопросы вида "Вам поручили сделать то-то, как вы это реализуете?" предполагают, что собеседуемый должен назвать общий алгоритм решения проблемы, и средства/технологии платформы, которые он при этом будет использовать. Код не надо писать))

Не смею больше томить! Вопросы под катом.

среда, 6 апреля 2011 г.

SharePoint 2010 Fluent Ribbon API

На мой взгляд, Ribbon - это абсолютно лучшее нововведение 2010й версии SharePoint. Но для разработчиков Ribbon не настолько удобен, как он удобен и привычен для пользователей. И это нужно исправлять!

Поэтому, представляю уважаемым читателям еще один мой OpenSource-проект, SharePoint 2010 Fluent Ribbon API!


Этот проект нацелен на упрощение работы с Ribbon'ом в SharePoint'е. Как известно, программное создание Ribbon'а требует выполнения большого числа действий, которые мне удалось спрятать в сборке FluentRibbon.

FluentRibbon 1.0 включают следующие основные классы:
  1. ContextualWebPart - базовый класс для веб-частей с контекстными вкладками риббона
  2. RibbonLayoutsPage - базовый класс для Application Page с риббоном

При этом, возможно динамическое создание риббона (например, в зависимости от привилегий текущего пользователя.

Chess WebPart

Вместе с FluentRibbon поставляется проект-пример ChessWebPart - веб-часть с javascript-шахматами, управление игрой и настройки в которой вынесены на риббон:

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

EnhancedWebPart

Выпустил свой первый OpenSource-проект на CodePlex. Не то, чтобы очень уж полезный, скорее "проба пера". И все-таки, кому-то может пригодиться.

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

Основная неприятность, с которой сталкиваешься при разработке веб-частей SharePoint - это конечно же, несовершенство системы редактирования их свойств:
  1. Поддерживаются только самые простые типы свойств.
  2. Нет встроенного механизма для реализации локализации названий и описаний свойств.
  3. Перечисления (enum) имеют существенные ограничения при отображении, в том числе отсутствие возможности для их локализации и невозможность отображения значений с пробелами, спецсимволами, а также чисел.
Поэтому, рано или поздно, все начинают пользоваться встроенным механизмом расширений редактора свойств - через EditorPart'ы. Но поскольку EditorPart'ы - вещь довольно низкоуровневая, и архитектурно неидеальная; то с этого момента начинается фактически велосипедописание.

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

Собственно, моя попытка реализовать эту идею и получила название EnhancedWebPart.

Основные преимущества EnhancedWebPart:
  1. Чтобы использовать функционал EnhancedWebPart, необходимо унаследовать собственную веб-часть от этого класса, и отметить специальными атрибутами нужные свойства. EnhancedWebPart самостоятельно создаст один или несколько (для каждого уникального значения атрибута Category) EditorPart'ов, и наполнит их соответствующими контролами.
  2. Простой и гибкий механизм для добавления новых отображаемых классов. Для этого используется MEF.
  3. В настоящее время в "библиотеке" отображаемых классов, поставляемой вместе с EnhancedWebPart, присутствуют следующие классы: bool, int, string, enum и SPUser.
  4. Поддерживается локализация и отображение любых значений в списках (через enum).
Недостаток пока вижу один: способ отображения зависит только от типа свойства, т.е. два способа отображения для string создать нельзя. Решения этой проблемы есть, возможно, в будущих версиях реализую.

На CodePlex'е я довольно подробно (правда, по-английски), с примерами, задокументировал этот проект. Так что вот, представляю:

четверг, 31 марта 2011 г.

Медленный DataTable?!

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

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

Простой тест!

Создадим широкую таблицу, 100 колонок (типа String). Добавим в неё пустяковый, в общем-то, объем данных - 3000 строк. Пробежимся по всей таблице, и проставим всем ячейкам значение "test".

foreach (DataRow row in table.Rows)
  foreach (DataColumn column in table.Columns)
    row[column] = "test";

Замерим время выполнения...
00:00:01.7110978

Ого! Нехило, для такой, вроде бы простой операции!? 2 секунды на каких-то жалких 3000 строк!?

И заметьте, никакого извращенного кода. Вполне нормальный код, который мог бы написать любой из нас. Единственная особенность - широкая таблица, много колонок.

Вот и у нас, в одном из совершенно реальных проектов, обнаружилась широкая таблица на 70 колонок. И с ней возникла похожая проблема. Пришлось немало повозиться, чтобы локализовать эту проблему и понять, в чем дело. И еще полчаса на то, чтобы выяснить, как это исправить.

Решение оказалось довольно неожиданным. Оказывается, в случае широких таблиц, быстрее удалить целую строку и добавить новую (фактически пересоздав таблицу), чем заполнять строки стандартным способом.

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

Measure("Standard method", 1, () =>
{
    foreach (DataRow row in table.Rows)
        foreach (DataColumn column in table.Columns)
        {
            int value = Convert.ToInt32(row[column]);
            if (value > 100)
                row[column] = value * 2;
            else
                row[column] = value * 3;
        }
});

Ничего сложного. Если значение больше 100, умножаем его на 2, иначе на 3.
А теперь то же самое, но с пересозданием строк:

Measure("Row recreate method", 1, () =>
{
    for (int i = 0; i < tempTable.Rows.Count; i++)
    {
        List<object> values = new List<object>();
        foreach (DataColumn column in tempTable.Columns)
        {
            int value = Convert.ToInt32(tempTable.Rows[0][column]);
            if (value > 100)
                values.Add(value * 2);
            else
                values.Add(value * 3);
        }

        tempTable.Rows.RemoveAt(0);
        tempTable.Rows.Add(values.ToArray());
    }
});

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

100 колонок, 3000 строк:
Standard method => 00:00:02.3351335
Row recreate method => 00:00:00.1030059


10 колонок, 30000 строк:
Standard method => 00:00:00.2970170
Row recreate method => 00:00:00.1980114


1 колонка, 300000 строк:
Standard method => 00:00:00.1740099
Row recreate method => 00:00:01.2810733


Результаты налицо: для большинства таблиц вариант с пересозданием строк будет работать очень быстро.

P. S.  Исходники метода Measure можно взять из статьи про производительность Lua Interface.

вторник, 29 марта 2011 г.

Интеграция SharePoint с внешними приложениями через SSIS

Стандартными средствами интеграции SharePoint-списков и сторонних приложений являются BCS (Business Connectivity Services, в 2007й версии - Business Data Catalog). Я думаю, большинство SharePoint-разработчиков не раз и не два имели дело с BCS. И вот по проcшествии некоторого времени, всегда оказывается, что для некоторых задач BCS не подходят! :(

Фактически, BCS без проблем позволяет решать только примитивные задачи, ну к примеру заCRUDить табличку SQL в список SharePoint. А чуть более сложные задачи требуют либо больших телодвижений, либо ну ОЧЕНЬ больших телодвижений... :(

Не вдаваясь в подробности, можно сказать, что BCS по-прежнему не идеален.

Антон Вишняков, за это ему отдельное спасибо, открыл мне глаза на еще один способ (помимо, конечно, "писать все руками") для интеграции данных SharePoint с внешними приложениями, который иногда может оказаться весьма полезным.

Способ заключается в использовании SQL Server Integration Services (SSIS) совместно с SharePoint List Source and Destination из OpenSource-проекта Microsoft SQL Server Community Samples: Integration Services.

Хочется немного рассказать об этом способе "на уровне теории", надеюсь эта информация будет полезна.

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


Пример схемы преобразования данных в SSIS
В качестве преобразований данных могут выступать, к примеру:
  • Разделение и соединение данных - как вертикально (по столбцам), так и горизонтально (аналогично union all).
  • Сортировка
  • Группировка
  • Подведение итогов
  • Создание сводных таблиц (Pivot table)
  • Собственные виды преобразований

В качестве источника данных и приемника данных могут выступать, в простейших случаях, таблицы и базы данных MS SQL, но также это могут быть Excel-таблицы, соединения OLE DB и  ADO.Net, и т.д. Помимо встроенных источников и приемников, можно создавать собственные.

Источник и приемник для списков SharePoint в состав SSIS не входят, они были написаны отдельно и представляют собой решение Visual Studio, частично на C#, частично на VB.Net. Причем, это решение подойдет даже для 2007го SharePoint'а, поскольку не использует Client Object Model, а действуют через веб-сервис lists.asmx.

Следует отметить, что сделано все довольно дотошно. В частности, ребята постарались озаботиться такой немаловажной штукой, как производительность:
  • Источник данных списка SharePoint запрашивает не весь список, а только затребованный его объем. Выборку колонок можно ограничить через дизайнер, а также можно задавать произвольные CAML-запросы.
  • Есть настройка, которая позволяет задать количество строк "за этап". Для некоторых "широких" (с большим числом столбцов) списков такое вот блочное чтение позволяет увеличить итоговую производительность.
  • Приемник данных обновляет только нужные колонки и только нужные строки (через Batch API).
И все это - не забываем, Open Source. Есть возможность допилить.

Если решите попробовать, пример по созданию SSIS-проекта для интеграции с SharePoint описан на MSDN.

P.S. Сам пока не пробовал, так что это все пока только в теории, но думаю, этот способ вполне имеет шансы на успех. Надеюсь, будет возможность где-нибудь попробовать на рабочем проекте, если это удастся - я отпишусь! :)