четверг, 26 мая 2011 г.

Если дохнет Skype

Ничего не делал, ничего не трогал. Skype перестал грузиться, пишет:

Problem signature:
  Problem Event Name:   APPCRASH
  Application Name: Skype.exe
  Application Version:  5.3.0.113
  Application Timestamp:    4dd67601
  Fault Module Name:    Skype.exe
  Fault Module Version: 5.3.0.113
  Fault Module Timestamp:   4dd67601
  Exception Code:   c0000005
  Exception Offset: 006ebe12
  OS Version:   6.1.7600.2.0.0.768.3
  Locale ID:    17417
  Additional Information 1: 0a9e
  Additional Information 2: 0a9e372d3b4ad19135b953a78882e789
  Additional Information 3: 0a9e
  Additional Information 4: 0a9e372d3b4ad19135b953a78882e789

Решение простое, удаляем файл в %userprofile%\AppData\Roaming\Skype\shared.xml

пятница, 20 мая 2011 г.

Веб-сервис, который работает с SharePoint


Иногда хочется чего-то необычного...

Нужно было из базы данных импортировать данные в список SharePoint. Сделать-то плёвое дело: сопоставление поля из БД и поля из SQL сделал и импортируй на здоровье. Но было ограничение - импортировать данные, как только их изменили в БД. Это значительно повышало замороченность задачки. Особенно учитывая, что импорт БД -> SharePoint 1000 записей и 12 полей проходил за 50-60 секунд.

Отвлечение: Почему не использовать BDC (который сейчас BCS) Потому что это зло =) Ни рабочий процесс прикрутить, ни связять с другим списком.

Мой извращённый ум, который теперь занимается унификацией архитектуры решений в госсекторе (проще говоря, старается во всём выделять универсальные компоненты и развивать их) придумал гениальную идею, которая стоила многих нервных клеток =) 

Есть определённые точки входа из которых изменяют данные в бд
Есть сама БД
Есть список SharePoint

ИДЕЯ: все точки входа (или сама база данных) при изменении данных вызывают веб-сервис, который начинает загрузку данных в SharePoint, а попутно ещё и статус загрузки показывает.

Реализация стандартная:
у веб-сервиса два метода. Первый запускает загрузку данных в отдельном потоке и возвращает идентификатор, по которому через второй метод можно получить состояние загрузки (просто в кеше сервера лежит и обновляется потоком что-то типа "идентификатор -> состояние").

Ну и как всегда всё упёрлось в SharePoint, уж не знаю при делах ли тут конкретная версия, но у меня был 2007.

Проблема первая: веб сервис не видит веб-сайт, т.е. когда делаем new SPSite выпадает 404 ошибка. Ну тут ошибка ожидаема была, просто не 404, а скорее что-то типа 401-403 (ошибка авторизации). Как ни странно, но именно в авторизации и была проблема. Решается легко: либо нормально настраиваем безопасность в IIS у веб-сервиса (передача данных пользователя), либо делаем веб-сервису олицетворение учёткой, которая имеет права на портале, либо запускаем веб-сервис в том же пуле приложений, что и у портала.

Проблема вторая: отняла много сил в первую очередь из-за неопытности в такого рода разработке. Зато многому начился ;) При SPListItem.Update вылетает ошибка, мол некорректные данные или их кто-то в другом месте изменил. Первое, самое стандартное решение - SPSecurity.RunWithElevatedPrivileges(() =>{...}) не прокатило, как ни странно. Второе, третье и двадцать четвёртое тоже. А вот двадцать пятое прокатило, вот и пишу, чтоб не забыть.
На деле оказывается решается вопрос очень просто, все процедуры по работе со списком стоит начинать с web.AllowUnsafeUpdates = true, ну и заканчивать с web.AllowUnsafeUpdates = false. Т.е. оказывается изменение данных в списке таким образом является не безопасным. Как-то додуматься почему так -  не смог, но методом перебора нашёл.

Ну собственно и всё. Разве ещё чуть разглагольствований о самой схеме загрузки.
Чем удобен такой подход с веб-сервисом? Удобно тем, что долговыполняющие операции мы делаем не в веб-странице/веб-части, а в отдельном сервисе. При переходе со страницы на страницу мы не потеряем данных о потоке, всегда его можем опросить на предмет состояния. Ну и конечно универсальность - в передаваемых аргументах методу импорта мы указываем привязки между базой данных и списком, этот веб-сервис можно использовать с любым списком (лишь бы привязки были). Чтобы можно было использовать ещё и с любой базой данных, нужно всего лишь использовать DbProviderFactory, ничего сложного в этом нет, разве что лишаемся пары удобных методов из классов подключения к базе данных SQL server.

А ещё можно этот веб-сервис поместить к веб-сервисам SharePoint, ну чтоб в одной куче лежал. По простому и по некорректному это делается просто: перекидываем файлы веб-сервиса в директории SharePoint на диске C:/Program files/....ну и как обычно. По правильному - это сгенерить кучку файлов .disco и .wsdl чтобы наш сервис был "discoverable by listing it in Spdisco.aspx" и имел "Web Services Description Language". Но тут чёрт ногу сломит...

четверг, 28 апреля 2011 г.

SharePoint 2010, SQL Server Analysis Services and Integration Services

Дано:
SharePoint 2010 Enterprise, как хранилище данных в списках.
SQL Server 2008 R2 Enterprise с установленными сервисами Analysis и Integration

Задача:
Хочется сделать Decomposition Tree по кубу данных как в красивых рекламных демках Микрософта.

Проблема:
Decomposition Tree строится только по кубу данных, который должен лежать на SQL Server'е. Как ни смешно, но простым путём с SQL Server до списка на SharePoint не достучаться:
1. Analysis Services не имеют в стандартной поставке провайдера для подключения к спискам, да и вообще к SharePoint.
2. Integration Services требуют написать собственный провайдер (или как там), для преобразования данных из SharePoint в данные SQL. Путь довольно сложный и долгий. Делаем по инструкции с MSDN, а результат нулевой - рекомендованная в первом пункте прога просто и главное молча не ставится.
3. Кто-то где-то на форумах MS советует юзать для этого power pivot, который поможет данные в SQL грузануть, но такое ощущение, что эти PowerPivot вообще для других целей.

Вывод:
Вариант, когда данные лежат в списках SharePoint, подсасываются в SQL CUBE, потом в Analysis Services и выводятся на SharePoint (PerfomancePoint) - не катит.
Собственнго напрашивается логичный вариант - почему бы данные вообще сразу не хранить в SQL, а на SharePoint их выводить через SharePoint BDC для редактирования и через PerfomancePoint для отчётов. Но есть одна проблема - это SharePoint BDC. Что в прошлом, что в текущем SharePoint этим уродством и наборов глюков, недоделок и багов пользоваться невозможно. Даже тупо разрулить виды аутентификации невозможно без редактирования блокнотом файла подключения, потому что в SharePoint Designer видите ли забыли в выпадающее меню добавить четвёртый, нужный всем вид аутентификации =).
Т.е. хрен вы выведите данные из SharePoint в куб и отчёт вставите опять на SharePoint.
Где, блин, хвалёная интеграция продуктов Microsoft?



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

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

Еда

Развлекался в этом месяце я так:
плов по-фергански

и так:
говядина, запечёная в соевом соусе, горчице и чёрном перце




пятница, 8 апреля 2011 г.

Просто смешно =)

Ольга Шамильевна, зачем вы лазите на моё резюме на hh? Мы же вроде как по хорошему разошлись? ;)

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

XSLT не закрывает DIV

Месяц мне не давала покоя мысль, что мои новости на портале оказываются вложенными друг в друга DIV'ами. Новости генеряться в виде XML, на экран выводятся через XSLT преобразования. написано всё верно, должны идти списком, но почему-то в первую новость вкладывается вторая, в которую вложена следующая и т.п.

Для примера ошибки рассмотрим такой код XSLT:
<div class="news_Info">
    <div class="news_Approve">
        <xsl:if test ="Состояние_утверждения != 0" >
            Новость не опубликована!
        </xsl:if>
    </div>
    <div class="news_CreateDate">
        <xsl:value-of select="Создан"/>
    </div>
    <div class="news_Author">
        <xsl:value-of select="Кем_создано"/>
    </div>
</div>

Проблема кроется в том, что если внутри DIV'а класса news_Approve не сработает xsl:if, т.е. не выдаст строку "Новость не опубликована!", то он окажется пустым:
<div class="news_Approve">
    </div>

А такой пустой DIV в браузер попадёт уже без закрывающего тега (вернее тег закрывающий будет, но в самом конце всего списка новостей). 
Решается просто: в каждый DIV, который может быть пустым дописываем по HTML'ому пробелу ( ). Не забываем, что в XSLT нельзя использовать амперсанд, так как он служебный символ. Несколько вариантов написать пробле HTML:
&amp;nbsp;
&#160;

Самый лучший вариант предложил мой программист: добавить в DIV такой код:
<div class="hidden">&#160;</div>
И разметка не разъедется, и DIV пустой не будет .

Интересная особенность, если мы делаем вот так:
<div class="news_Approve"></div>
то закрывающий тэг не теряется, а если между ними вставить хоть пробел, хоть таб, то закрывающий тег потеряется =)

Update: есть более умный вариант, о котором все забыли:
<xsl:output method="html" />
=))