Part 3 – Sign Out/Sign in as a Different User
A project I am working on called for a custom implementation of the SharePoint Welcome menu control. The replacement control needed to provide the following:
- Implement the look and behaviors that the designers created.
- Exclude some default SharePoint menu items (such as My Regional Settings).
- Reuse some existing SharePoint menu items (such as Sign Out/Sign in as a Different User).
- Allow for the addition of other custom menu items in the future.
- Display thumbnail of the user’s profile picture.
I had to create a control that looked and behaved like the following:
The designers came up with some clean, semantic markup married with some jquery, for me to start from:
<div class="header">
<img class="header-logo" src="/images/header_logo.png" alt="" width="169" height="78" />
<div class="header-bar">
<div class="profile_menu">
<a href="#" class="profile_btn">
<span class="image"><img src="" style="width:20px;height:20px" /></span>
<span class="name">John Doe</span>
<span class="arrow"></span>
</a>
<div class="profile_dropdown">
<div class="dropdown_bkgrd">
<ul>
<li>Edit Profile</li>
<li>My Site</li>
<li>Log Out</li>
<li>Sign in as a Different User</li>
</ul>
</div>
</div>
</div>
</div>
</div>
This is part 3 of a three part series.
- Part 1 – Overview, Profile Picture, and User Name
- Part 2 – Edit Profile and My Site links
- Part 3 – Sign Out/Sign in as a Different User
Building the Sign Out Links
The Sign Out and Sign in as a Different User menu items are rendered by the PersonalActions control, in two methods (from Reflector):
private void SetLoginAsDifferentUserMenuItemGoToPageUrl()
{
MenuItemTemplate menuItem = base.GetMenuItem("ID_LoginAsDifferentUser");
if (menuItem != null)
{
if (SPSecurity.AuthenticationMode == AuthenticationMode.None)
{
menuItem.Visible = false;
}
else
{
string serverRelativeUrlFromUrl = this.Web.GetServerRelativeUrlFromUrl("_layouts/closeConnection.aspx?loginasanotheruser=true");
menuItem.ClientOnClickScript = "javascript:LoginAsAnother('" + SPHttpUtility.EcmaScriptStringLiteralEncode(serverRelativeUrlFromUrl) + "', 0)";
}
}
}
private void SetSignOutMenuItemGoToPageUrl()
{
MenuItemTemplate menuItem = base.GetMenuItem("ID_Logout");
if (menuItem != null)
{
if (SPSecurity.AuthenticationMode == AuthenticationMode.None)
{
menuItem.Visible = false;
}
else
{
menuItem.ClientOnClickNavigateUrl = this.Web.GetServerRelativeUrlFromUrl("_layouts/SignOut.aspx");
}
}
}
The “Sign Out” link points to “_layouts/SignOut.aspx”, and “Sign in as a Different User” points to “_layouts/closeConnection.aspx”.
To leverage this, I again adjusted the ASCX markup to include some PlaceHolder and LinkButton controls:
<div class="profile_dropdown">
<asp:PlaceHolder ID="placeHolderUserID" runat="server"></asp:PlaceHolder>
<div class="dropdown_bkgrd">
<ul>
<asp:PlaceHolder ID="placeHolderEditProfile" runat="server"><li><asp:LinkButton ID="linkButtonEditProfile" runat="server" EnableViewState="false" Text="Edit Profile"></asp:LinkButton></li></asp:PlaceHolder>
<asp:PlaceHolder ID="placeHolderMySite" runat="server"><li><asp:LinkButton ID="linkButtonMySite" runat="server" EnableViewState="false" Text="My Site"></asp:LinkButton></li></asp:PlaceHolder>
<li><asp:LinkButton ID="linkButtonLogOut" runat="server" EnableViewState="false" Text="Sign Out"></asp:LinkButton></li>
<li><asp:LinkButton ID="linkButtonLoginAsDifferentUser" runat="server" EnableViewState="false" Text="Sign in as a Different User"></asp:LinkButton></li>
</ul>
</div>
</div>
And then here is some code-behind that re-creates the output from the PersonalActions control:
// Login as another user
string loginAsAnotherUserUrl = this.ResolveClientUrl("~/_layouts/closeConnection.aspx?loginasanotheruser=true");
linkButtonLoginAsDifferentUser.OnClientClick = string.Format("LoginAsAnother('{0}', 0);return false;", SPHttpUtility.EcmaScriptStringLiteralEncode(loginAsAnotherUserUrl));
// Sign out
string signOutUrl = this.ResolveClientUrl("~/_layouts/SignOut.aspx");
linkButtonLogOut.OnClientClick = "GoToPage('" + SPHttpUtility.EcmaScriptStringLiteralEncode(signOutUrl) + "');return false;";
Summary
In this post, we deconstructed the PersonalActions control further to re-create the Sign Out and Sign in as a Different User menu items.
Our Final ASCX markup is:
<%@ Assembly Name="$SharePoint.Project.AssemblyFullName$" %>
<%@ Assembly Name="Microsoft.Web.CommandUI, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="asp" Namespace="System.Web.UI" Assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" %>
<%@ Import Namespace="Microsoft.SharePoint" %>
<%@ Register Tagprefix="WebPartPages" Namespace="Microsoft.SharePoint.WebPartPages" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="CustomWelcomeMenuControl.ascx.cs" Inherits="CustomWelcomeMenu.ControlTemplates.CustomWelcomeMenu.CustomWelcomeMenuControl" %>
<div class="header">
<img class="header-logo" src="/images/header_logo.png" alt="" width="169" height="78" />
<div class="header-bar">
<div class="profile_menu">
<a href="#" class="profile_btn">
<span class="image"><asp:Image ID="imageProfilePicture" runat="server" Width="20px" Height="20px" /></span>
<span class="name"><asp:PlaceHolder ID="placeHolderWelcomeName" runat="server"></asp:PlaceHolder></span>
<span class="arrow"></span>
</a>
<div class="profile_dropdown">
<asp:PlaceHolder ID="placeHolderUserID" runat="server"></asp:PlaceHolder>
<div class="dropdown_bkgrd">
<ul>
<asp:PlaceHolder ID="placeHolderEditProfile" runat="server"><li><asp:LinkButton ID="linkButtonEditProfile" runat="server" EnableViewState="false" Text="Edit Profile"></asp:LinkButton></li></asp:PlaceHolder>
<asp:PlaceHolder ID="placeHolderMySite" runat="server"><li><asp:LinkButton ID="linkButtonMySite" runat="server" EnableViewState="false" Text="My Site"></asp:LinkButton></li></asp:PlaceHolder>
<li><asp:LinkButton ID="linkButtonLogOut" runat="server" EnableViewState="false" Text="Sign Out"></asp:LinkButton></li>
<li><asp:LinkButton ID="linkButtonLoginAsDifferentUser" runat="server" EnableViewState="false" Text="Sign in as a Different User"></asp:LinkButton></li>
</ul>
</div>
</div>
</div>
</div>
</div>
Our Final ASCX code-behind is:
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.Utilities;
namespace CustomWelcomeMenu.ControlTemplates.CustomWelcomeMenu
{
public partial class CustomWelcomeMenuControl : UserControl
{
protected void Page_PreRender(object sender, EventArgs e)
{
// Username
PostCacheSubstitutionText welcomeText = new PostCacheSubstitutionText();
welcomeText.TextType = PostCacheSubstitutionTextType.UserName;
placeHolderWelcomeName.Controls.Add(welcomeText);
// Profile picture
SPList userInfoList = SPContext.Current.Web.GetCatalog(SPListTemplateType.UserInformation);
SPListItem userProfileItem = userInfoList.GetItemById(SPContext.Current.Web.CurrentUser.ID);
if (userProfileItem["Picture"] == null || string.IsNullOrEmpty(userProfileItem["Picture"].ToString()))
{
// Use default picture (or replace with another)
imageProfilePicture.ImageUrl = "/_layouts/images/PERSON.GIF";
}
else
{
SPFieldUrlValue value = new SPFieldUrlValue(userProfileItem["Picture"].ToString());
imageProfilePicture.ImageUrl = value.Url;
}
string myProfileUrl = Context.Items["SocialData$ProfileURL"] as string;
string mySiteHostUrl = Context.Items["SocialData$MySiteHostURL"] as string;
if (!Page.IsPostBack)
{
myProfileUrl = Context.Items["SocialData$ProfileURL"] as string;
ViewState[Constants.VIEWSTATE_PROFILE_URL] = myProfileUrl;
mySiteHostUrl = Context.Items["SocialData$MySiteHostURL"] as string;
ViewState[Constants.VIEWSTATE_MYSITE_URL] = mySiteHostUrl;
}
else
{
myProfileUrl = ViewState[Constants.VIEWSTATE_PROFILE_URL] as string;
mySiteHostUrl = ViewState[Constants.VIEWSTATE_MYSITE_URL] as string;
}
if (string.IsNullOrEmpty(mySiteHostUrl))
{
// No MySite host, or user does not have rights to view profile page...
placeHolderMySite.Visible = false;
}
else
{
// User has a MySite, show the link to it...
placeHolderMySite.Visible = true;
linkButtonMySite.OnClientClick = string.Format("STSNavigate2(event, '{0}');return false;", SPHttpUtility.EcmaScriptStringLiteralEncode(mySiteHostUrl));
}
if (string.IsNullOrEmpty(myProfileUrl))
{
// Use the SharePoint foundation profile page, since the MySite host is not available
PostCacheSubstitutionText pt = new PostCacheSubstitutionText();
pt.TextType = PostCacheSubstitutionTextType.UserId;
pt.PrefixHtml = "<script type="text/javascript">n//<![CDATA[nvar _spUserId=";
pt.SuffixHtml = ";n//]]>n</script>";
placeHolderUserID.Controls.Add(pt);
string serverRelativeUrlFromUrl = this.ResolveClientUrl("~/_layouts/userdisp.aspx?Force=True&ID=");
linkButtonEditProfile.OnClientClick = "GoToPage('" + SPHttpUtility.EcmaScriptStringLiteralEncode(serverRelativeUrlFromUrl) + "' + _spUserId);return false;";
}
else
{
// Use the MySite profile page...
linkButtonEditProfile.OnClientClick = string.Format("STSNavigate2(event, '{0}');return false;", SPHttpUtility.EcmaScriptStringLiteralEncode(myProfileUrl));
}
// Login as another user
string loginAsAnotherUserUrl = this.ResolveClientUrl("~/_layouts/closeConnection.aspx?loginasanotheruser=true");
linkButtonLoginAsDifferentUser.OnClientClick = string.Format("LoginAsAnother('{0}', 0);return false;", SPHttpUtility.EcmaScriptStringLiteralEncode(loginAsAnotherUserUrl));
// Sign out
string signOutUrl = this.ResolveClientUrl("~/_layouts/SignOut.aspx");
linkButtonLogOut.OnClientClick = "GoToPage('" + SPHttpUtility.EcmaScriptStringLiteralEncode(signOutUrl) + "');return false;";
}
}
}
Hopefully you find this useful, and can take it further if need be. Leave comments if you have any questions.















very well done, i would have like to seen the css that goes along with this.
Nice work. However I want to know how you make the div to be a dropdown. Thanks.