- Задание -
При использовании действия "Войти под другим пользователем" новый пользователь должен быть перенаправлен на главную странцу (рис. 1), а не на ту, с которой было выполнено действие.
- Анализ -
Кнопка, которую мы анализируем находится в пользовательском контроле Welcome.ascx, который в свою очередь находится в папке CONTROLTEMPLATES. Рассмотрим его код разметки (часть кода была опущена):
<SharePoint:PersonalActions
AccessKey="<%$Resources:wss,personalactions_menu_ak%>"
ToolTip="<%$Resources:wss,open_menu%>"
runat="server"
ID="ExplicitLogout"
Visible="false">
<CustomTemplate>
<SharePoint:FeatureMenuTemplate
runat="server"
FeatureScope="Site"
Location="Microsoft.SharePoint.StandardMenu"
GroupId="PersonalActions"
ID="ID_PersonalActionMenu"
UseShortId="true">
<%-- Тут пункты меню --%>
<SharePoint:MenuItemTemplate
runat="server"
id="ID_LoginAsDifferentUser"
Text="<%$Resources:wss,personalactions_loginasdifferentuser%>"
Description="<%$Resources:wss,personalactions_loginasdifferentuserdescription%>"
MenuGroupId="200"
Sequence="100"
UseShortId="true" />
<%-- И тут пункты меню --%>
</SharePoint:FeatureMenuTemplate>
</CustomTemplate>
</SharePoint:PersonalActions>
Итак, мы нашли необходимый нам пункт меню с уникальным идентификатором ID_LoginAsDifferentUser, но почему-то отсутствует инициализация свойства ClientOnClickScript. Сразу промелькнула мысль, что инициализация осуществляется в code behind. Смотрим туда, но интересного ничего не находим. Смотрим методы дочерних элементов и что мы видим (ILSpy 1.0.0.1000):
public sealed class PersonalActions : ToolBarMenuButton, IPreRenderOverride
{
[SharePointPermission(SecurityAction.Demand, ObjectModel = true)]
protected override void CreateChildControls()
{
/* Тут ничего интересного. */
this.SetLoginAsDifferentUserMenuItemGoToPageUrl();
this.SetSignOutMenuItemGoToPageUrl();
this.HandleRequestForAccessMenuItem();
}
private void SetLoginAsDifferentUserMenuItemGoToPageUrl()
{
MenuItemTemplate menuItem = base.GetMenuItem("ID_LoginAsDifferentUser");
if (menuItem != null)
{
if (SPSecurity.AuthenticationMode == AuthenticationMode.None)
{
menuItem.Visible = false;
return;
}
string serverRelativeUrlFromUrl =
this.Web.GetServerRelativeUrlFromUrl("_layouts/closeConnection.aspx?loginasanotheruser=true");
menuItem.ClientOnClickScript = "javascript:LoginAsAnother('" +
SPHttpUtility.EcmaScriptStringLiteralEncode(serverRelativeUrlFromUrl) + "', 0)";
}
}
}
Вуаля, то что нам нужно! Однако зоркий глаз программиста увидит, что унаследоваться от данного класса нельзя, соответственно необходимо искать другие подходы для переопределения данной функциональности. Можно, конечно, поправить JS-функцию LoginAsAnother() в init.js, но я бы не советовал трогать встроенную функциональность, лучше пойти в обход и "склонировать" (об этом далее).
- Действия -
Мне было легче, потому что у меня был доступ к исходникам решения, в котором была мастер-страница с готовой разметкой, в которой красовалось:
<wssuc:Welcome id="IdWelcome" runat="server" EnableViewState="false" />
Далее создаём свой пользовательский контрол в mapped-папке CONTROLTEMPLATES, например, с названием Welcome.ascx (рис. 2).
Разметку копируем с Welcome.ascx. Далее заходим в Welcome.ascx.cs и добавляем следущее:
/* Тут атрибуты, если необходимо */
public partial class WelcomeControl : Welcome
{
private const string LoginAsAnotherUserId = "W_ID_LoginAsDifferentUser";
///
/// Called by the ASP.NET page framework to notify server controls that use composition-based implementation to create any child controls they contain in preparation for posting back or rendering.
///
protected override void CreateChildControls()
{
base.CreateChildControls();
this.SetLoginAsDifferentUserMenuItemGoToPageUrl();
}
///
/// Builds functionality for the control that performs "Sign in as different user" action.
///
protected virtual void SetLoginAsDifferentUserMenuItemGoToPageUrl()
{
MenuItemTemplate menuItem = this.ExplicitLogout.GetMenuItem(LoginAsAnotherUserId);
if (menuItem != null)
{
if (SPSecurity.AuthenticationMode == AuthenticationMode.None)
{
menuItem.Visible = false;
return;
}
SPWeb contextWeb = this.ExplicitLogout.Web;
string serverRelativeUrlFromUrl = SPUrlUtility.CombineUrl(
contextWeb.Url,
"/_layouts/closeConnection.aspx?loginasanotheruser=true");
menuItem.ClientOnClickScript = string.Format(
"javascript:WLoginAsAnother('{0}', '{1}', 0);",
SPHttpUtility.EcmaScriptStringLiteralEncode(serverRelativeUrlFromUrl),
contextWeb.Site.Url);
}
}
}
}
Значение поля LoginAsAnotherUserId - новый идентификатор действия, которое уже мы будем переопределять. Старый идентификатор просто заменяем на новый (в разметке). В методе PersonalActions.SetLoginAsDifferentUserMenuItemGoToPageUrl() стоит проверка на null если старого пункта меню не найдено, соответственно исключений нам не грозит. Далее, необходимо создать аналог JS-функции LoginAsAnother(), я назвал её WLoginAsAnother и принимает она уже не 2 параметра, а 3 (об этом далее). Создаём JS-файл (рис. 3), которые в дальнейшем будет зарегистрирован на мастер-странице через SctipLink (или можно зарегистрировать его в ascx-файле, не имеет значения).
Вот его код:
function ULSWInit() {
var o = new Object;
o.ULSTeamName = "Project name"; //// Укажите своё имя проекта.
o.ULSFileName = "mkb.init.js";
return o;
}
function WLoginAsAnother(url, sourceUrl, bUseSource) {
ULSWInit: ;
document.cookie = "loginAsDifferentAttemptCount=0";
if (bUseSource == "1") {
GoToPage(url);
}
else {
var ch = url.indexOf("?") >= 0 ? "&" : "?";
url += ch + "Source=" + escapeProperly(sourceUrl);
STSNavigate(url);
}
}
Как мы видим, с какой бы страницы пользователь не вышел, он всегда будет перенаправлен на страницу, которую мы указали (contextWeb.Site.Url). Теперь топаем на мастер-страницу, регистрируем вместо стандартного Welcome.ascx только что созданный, регистрируем JS-файл и радуемся. В данном случае мы в выигрыше по двум причинам:
- не затронули стандартной функциональности и при необходимости можем безболезненно вернуть всё обратно.
- имеем доступ ко всем встроенным пунктам меню и можем добавлять новые прямо в разметку (без CustomAction).
Если будут вопросы - пишите в комментариях. Возможно, статья получилась немного сумбурная...



Комментариев нет:
Отправить комментарий