Архив рубрики ‘C#’

reSP — great Resharper plugin from SubPoint Solutions.

Makes Your SharePoint solutions code more stable and robust:
http://subpointsolutions.com/resp/

я обновил Sharepoint EventHandlerExplorer 2013/2016, утилиту которая позволяет управлять обработчиками событий без использования SharePoint-фич. Позволяет привязывать ресиверы к вебам, спискам/библиотекам SharePoint, а также к контент-тайпам:

Скачать

Описание:

Фичи позволяют привязывать обработчики только к известным типам контента(хрестоматийный пример – список “Announcements”):

<Receivers ListTemplateId="104">

Но такое декларативное развёртывание действует на весь scope и не позволяет к примеру привязать два обработчика к разным Announcement-спискам. Также не позволяет регистрировать обработчик для списка с неизвестным Id.

Изначально первая версия EventHandlerExplorer была создана Patrick Tisseghem и работала с третьей версией WSS. В Windows 2012(в .NET 4) появился новый глобальный кеш сборок, и исчезла возможность “перетягивать” мышью DLL-ки в GAC. Вместо drag-n-drop теперь рекомендуется использовать powershell:

[System.Reflection.Assembly]::Load('System.EnterpriseServices, Version = 4.0.0.0, Culture = neutral, PublicKeyToken = b03f5f7f11d50a3a');
$publish = New-Object System.EnterpriseServices.Internal.Publish;
$publish.GacInstall('$fullpath');

я добавил обёртку для развёртывания через powershell и поддержку 2013 и 2016 версий SharePoint on-premise

Реклама

Есть вебчасть, содержащая внутри себя меню PeopleEditor. Столкнулся с тем что для анонимных пользователей она недоступна:

control is not available

Спасибо Karel Hájek, который раскопал рефлектором что дело в дополнительной проверке, которая происходит на этапе рендеринга. Для отображения не хватает пермишна “BrowseUserInfo”, который по умолчанию выключен для анонимных юзеров, а веб-интерфейс не позволяет его выдать.

does_user_have_permissions

Karel предлагает подредактировать базу данных контента и разрешить анонимные запросы в Active Directory.

Намного проще это сделать через Powershell-скрипт, тем более что редактирование базы контента напрямую это очень bad-practice 🙂

Подключаем консоль, получим текущие разрешения и добавим к ним SPBasePermissions.BrowseUserInfo:

$sharePointSnapin = Get-PSSnapin | Where-Object { $_.Name -eq "Microsoft.SharePoint.PowerShell"}
if($sharePointSnapin -eq $null)
{
 Add-PSSnapin Microsoft.SharePoint.PowerShell 
}


$web = Get-SPWeb http://portal/web/

$web.AnonymousPermMask64;
# output: ViewListItems, ViewVersions, ViewFormPages, Open, ViewPages, UseClientIntegration


$web.AnonymousPermMask64 = "$rights, BrowseUserInfo";
$web.Update();

Теперь PeoplePicker рендерится для всех пользователей(для того чтобы он ещё и работал надо включить запросы в AD):

people_picker_rendered

Есть система багтреккинга, сделанная на Sharepoint с использованием Infopath-форм.

Формы имеют несколько копий и в зависимости от принадлежности сотрудника в AD, ему подставляется своя копия и люди из разных отделов могут редактировать только свои поля:

image

Задача:

После экспорта узла из вида пропало поле «Статуса». То есть на форме оно есть, а в колонках видов и настройках списка уже нет.

Решение:

— Переопубликовать форму в Infopath Designer(колонка должна появиться, но без значений).

— Обновить все элементы списка, чтобы значения появились в видах SharePoint.

Программно это можно сделать например так

  using (SPSite site = new SPSite("http://server/webName "))
 using (SPWeb web = site.OpenWeb())
 {
 SPList list = web.GetList("http://server/webname/libName/");
 foreach (SPListItem item in list.Items)
 {
 try
 {
 Console.Write("Updating " + item.ID.ToString());
 item.SystemUpdate();
 Console.WriteLine(".. Ok.");
 }
 catch (Exception ex)
 {
 Console.WriteLine(ex.ToString());
 }
 }
 } 

или через Powershell:

$web = Get-SPWeb -identity "http://server/webName"
 
$list = $web.Lists["listName"] 

$list.Items | ForEach-Object { Write-Host "Updating " $_.Name; $_.SystemUpdate(); }

$web.Dispose()

p.s.: при этом пользовательские виды с участием этих “пропавших и возвращённых” полей возможно прийдётся пересоздать

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

Это extension-класс для SPListItem. Основа это пост на stackoverflow , я лишь добавил от себя ещё пару функций для работы с файлами — добавление файла и функцию CopyTo, для «тихого» копирования файла.

using Microsoft.SharePoint;

public static class SPListItemExtensions
{
    /// <summary>
    /// Provides ability to update list item without firing event receiver.
    /// </summary>
    /// <param name="item">list item</param>
    /// <param name="doNotFireEvents">Disables firing event receiver while updating item.</param>
    public static void Update(this SPListItem item, bool doNotFireEvents)
    {
        SPItemEventReceiverHandling rh = new SPItemEventReceiverHandling();
        if (doNotFireEvents)
        {
            try
            {
                rh.DisableEventFiring();
                item.Update();
            }
            finally
            {
                rh.EnableEventFiring();
            }
        }
        else
        {
            item.Update();
        }
    }

    /// <summary>
    /// Provides ability to update list item without firing event receiver.
    /// </summary>
    public static void SystemUpdate(this SPListItem item, bool incrementListItemVersion, bool doNotFireEvents)
    {
        SPItemEventReceiverHandling rh = new SPItemEventReceiverHandling();
        if (doNotFireEvents)
        {
            try
            {
                rh.DisableEventFiring();
                item.SystemUpdate(incrementListItemVersion);
            }
            finally
            {
                rh.EnableEventFiring();
            }
        }
        else
        {
            item.SystemUpdate(incrementListItemVersion);
        }
    }

    /// <summary>
    /// Provides ability to copy file from list item without firing event receiver.
    /// </summary>
    public static void CopyTo(this SPFile file, string strNewUrl, bool bOverWrite, bool doNotFireEvents)
    {
        SPItemEventReceiverHandling rh = new SPItemEventReceiverHandling();
        if (doNotFireEvents)
        {
            try
            {
                rh.DisableEventFiring();
                file.CopyTo(strNewUrl, bOverWrite);
            }
            finally
            {
                rh.EnableEventFiring();
            }
        }
        else
        {
            file.CopyTo(strNewUrl, bOverWrite);
        }
    }


    /// <summary>
    /// Provides ability to update list item without firing event receiver.
    /// </summary>
    public static void SystemUpdate(this SPListItem item, bool doNotFireEvents)
    {
        SPItemEventReceiverHandling rh = new SPItemEventReceiverHandling();
        if (doNotFireEvents)
        {
            try
            {
                rh.DisableEventFiring();
                item.SystemUpdate();
            }
            finally
            {
                rh.EnableEventFiring();
            }
        }
        else
        {
            item.SystemUpdate();
        }
    }

    /// <summary>
    /// Provides ability to add file to sharepoint library without firing event receiver.
    /// </summary>
    public static SPFile AddFile(SPFileCollection spFileCollection, string destPathToFile, byte[] binFileData, bool overwrite, bool doNotFireEvents)
    {
        SPItemEventReceiverHandling rh = new SPItemEventReceiverHandling();
        if (doNotFireEvents)
        {
            try
            {
                rh.DisableEventFiring();
                SPFile addedFile = spFileCollection.Add(destPathToFile, binFileData, overwrite);
                return addedFile;
            }
            finally
            {
                rh.EnableEventFiring();
            }
        }
        else
        {
            SPFile addedFile = spFileCollection.Add(destPathToFile, binFileData, overwrite);
            return addedFile;
        }
    }

    private class SPItemEventReceiverHandling : SPItemEventReceiver
    {
        public SPItemEventReceiverHandling() { }

        new public void DisableEventFiring()
        {
#pragma warning disable 612,618
            base.DisableEventFiring();
#pragma warning restore 612,618
        }

        new public void EnableEventFiring()
        {
#pragma warning disable 612,618
            base.EnableEventFiring();
#pragma warning restore 612,618
        }
    }
}