Thursday, November 12, 2015

Conditional Formatting in SharePoint 2013/2016 and Office 365

Conditional formatting has always been a pain point in SharePoint 2013 and SharePoint Online (Office 365). Especially for those working with SharePoint 2007 and 2010 where you were able to do conditional formatting using SharePoint Designer. In SharePoint 2013 and Office 365 this functionality is gone.

You can still use different JavaScript hacks (i.e. use some calculated columns + JavaScript to apply conditional formatting to the row). There are lots of blog posts about that, but the main problems with all of those are amount of time you have to invest to produce the result and the fact that it is practically out of bounds of the regular SharePoint user.

My company Sharepointalist was diligently working on making conditional formatting features accessible and usable by the regular SharePoint user. We have done an enormous work and I am very proud to showcase some of the features of our new product SharePoint List Booster.
List Booster works as an add-on on your regular out of the box SharePoint list views (any lists and document libraries). It allows you to style your list, apply color schemes, manage font-styles and colors - all on top of you regular SharePoint user interface.

Using List Booster you can easily apply different conditional formatting rules including:

  • Text Rules;
  • Date Rules;
  • Numeric Rules (including currency);
  • Ranking Rules (Top, Bottom, Top %, Bottom %);
  • Averages Rules (equals average, above average, below average, etc.)

You can also use various indicators allowing to create various traffic lights.

Tuesday, June 9, 2015

Resize columns in SharePoint lists and document libraries

User experience in SharePoint is one of the key concerns for many SharePoint users. My company - Sharepointalist decided to upgrade SharePoint user experience in one of the most frequently used SharePoint features - lists and document libraries.

Sharepointalist recently released a new product – SharePoint List Booster. It’s a new generation SharePoint add-on, created using JavaScript and CSS only – no server-side code – works for both SharePoint Online (Office 365) and SharePoint 2013. List Booster enhances out of the box SharePoint user experience enabling user to do the following, when working with lists and document libraries:

  • resize columns (including auto-size by double click) - on any list view;
  • change of font styles, text alignment, color and background for columns and headers;
  • real paging (showing total amount of pages and clicking on the page number same way as in Google), visible both on top and bottom of the list view;
  • table styles color schemes – same as you have in Microsoft Excel or Word;
  • it all works both in regular view and in quick edit mode.

All those features are very intuitive and easy to use by the end users. List Booster helps a lot with the SharePoint adoption and increases performance when working with large lists and document libraries.

You can check out short video about the product at http://www.spbooster.com

If you wish to be able to easily change column sizes, text and background colors, font styles and alignment of your SharePoint lists and document libraries, you have to check out this product.

Tuesday, January 13, 2015

Eliminate Confusion with Time Zones in SharePoint Online and SharePoint 2013 On-Premises

Many companies with users spread across multiple time zones experience issues with the dates when using SharePoint on-premises and SharePoint Online. By default SharePoint users see all dates and times in the time zone of the site, so all the visitors has to guess what is the actual time of all those modify dates and event start times. There are multiple ways to eliminate this confusion:

  • Out of the box - Update your user profile to always show SharePoint dates in your current time zone. While being a great feature, it is somewhat hidden from the user and relies on self service (user has to do that by himself)
  • SharePoint Time Zone App - my company (Sharepointalist) recently published new free SharePoint App (works both on-premises and SharePoint online), which allows you to place small widget (app part) on any SharePoint page, and it will show user time zone of that page. It means that when you create a calendar and share the link with all users, they will immediately see what time zone is that in. This app also provides a quick link to configure user profile to see all dates in the right time zone, which is very convenient to the user. Please try this app, it is totally free and very easy to install and use.

Attaching couple screen shots of the app

Monday, March 25, 2013

Site Feed Web Part Newsfeed Title

If you were ever wondering how do you change "Newsfeed" title when using SiteFeed web part... It is a predefined resource located in profilebrowserscriptres.resx and profilebrowserscriptres.en-US.resx (depends on your locale).


  <data name="SiteFeedTitleName" xml:space="preserve">
    <value>Newsfeed</value>
    
  </data>
While you can tweak it, it is highly not recommended, as changes to Microsoft files, located in 15 HIVE could be overwritten during service pack deployment, migrations, etc.

Thursday, March 21, 2013

Setting Custom ListFormWebPart Parameters in List Definition

In order to set custom ListFormWebPart parameters when defining list definition schema, you need to modify Form tag in schema.xml. Please refer to the following sample, used to add CSRRenderMode property to ListFormWebPart and set it to ServerRender:

<Form Type="NewForm" Url="NewForm.aspx" SetupPath="pages\form.aspx" WebPartZoneID="Main" UseDefaultListFormWebPart="False">
    <WebParts>
      <AllUsersWebPart WebPartZoneID="Main" WebPartOrder="1">
        <![CDATA[
<WebPart xmlns="http://schemas.microsoft.com/WebPart/v2">
  <Assembly>Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, 
         PublicKeyToken=71e9bce111e9429c</Assembly>                         
  <TypeName>Microsoft.SharePoint.WebPartPages.ListFormWebPart</TypeName>
  <PageType>PAGE_NEWFORM</PageType>
  <CSRRenderMode xmlns="http://schemas.microsoft.com/WebPart/v2/ListForm">ServerRender</CSRRenderMode>

</WebPart>]]>
      </AllUsersWebPart>
    </WebParts>
</Form>

You can change Microsoft.SharePoint assembly reference to 14.0.0.0 or 12.0.0.0 to use it with SharePoint 2010 or SharePoint 2007 respectfully.

SharePoint 2013 Event Receiver Redirect

It used to be a standard practice to use redirect in event receivers in SharePoint 2010 and SharePoint 2007. SharePoint 2013 has some changes in this functionality.

Redirect Option Availability

No redirect options available for ItemAdded, ItemUpdated and ItemDeleted.

Some redirect options available for ItemAdding, ItemUpdating and ItemDeleting. They are only available when the form, which initiates an event, is being rendered in CSRRenderMode.ServerRender mode. Otherwise list forms are committed through asynchronous XmlHttpRequests, and redirect options are not available.

CancelWithRedirectUrl - DOES NOT WORK

The following code does function:

properties.RedirectUrl = "http://www.google.com";
properties.Status = SPEventReceiverStatus.CancelWithRedirectUrl;
Compiler is issuing the following warning:
'Microsoft.SharePoint.SPEventReceiverStatus.CancelWithRedirectUrl' is obsolete: '"Default list forms are committed through asynchronous XmlHttpRequests, so redirect urls specified in this way aren't followed by default. In order to force a list form to follow a cancelation redirect url, set the list form web part's CSRRenderMode property to CSRRenderMode.ServerRender"'. If you need to figure out how to set CSRRenderMode.ServerRender property for the form automatically (in list definition), please refer to my other blog post

SPUtility.Redirect - DOES NOT WORK

SPUtility.Redirect does not work in Event Receivers any more. It actually throws an exception. The reason - SPUtility.Redirect relies on HttpContext.Current, which does not exist at that point of execution. Tested with different CSRRenderMode settings.

[SubsetCallableExcludeMember(SubsetCallableExcludeMemberType.UnsupportedExternalType)]
public static bool Redirect(string url, SPRedirectFlags flags, HttpContext context, string queryString)
{
    string urlRedirect = null;
    bool flag = DetermineRedirectUrl(url, flags, context, queryString, out urlRedirect);
    if (flag)
    {
        bool flag2 = SPRedirectFlags.DoNotEndResponse == (flags & SPRedirectFlags.DoNotEndResponse);
        bool flag3 = DeltaPage.IsDeltaRedirectDisabled(context);
        if (!flag3 && DeltaPage.IsRenderingDelta(context))
        {
            DeltaPage handler = context.Handler as DeltaPage;
            if (handler != null)
            {
                handler.Redirect(context, urlRedirect, !flag2);
            }
            return flag;
        }
        bool flag4 = ((!flag3 && IsMDSEnabled(context)) && (!IsDialogUrl(urlRedirect) && IsBrowserRequest(context.Request))) && (SPRedirectFlags.AttemptMDSNavigate == (flags & SPRedirectFlags.AttemptMDSNavigate));
        bool flag5 = false;
        if (flag4)
        {
            flag5 = DeltaPage.AttemptMDSRedirect(context, urlRedirect, !flag2);
        }
        if (flag4 && flag5)
        {
            return flag;
        }
        SPLongOperation currentLongOperation = SPLongOperation.CurrentLongOperation;
        if (currentLongOperation != null)
        {
            currentLongOperation.End(url, flags, context, queryString);
            return flag;
        }
        if (Utility.IsClientQuery(context) && !Utility.IsRedirectAllowed(context))
        {
            RedirectException exception = new RedirectException(urlRedirect);
            context.Items[typeof(RedirectException)] = exception;
            throw exception;
        }
        try
        {
            context.Response.Redirect(urlRedirect, !flag2);
        }
        catch (Exception exception2)
        {
            if ((exception2 is ThreadAbortException) && !flag2)
            {
                throw;
            }
            ULS.SendTraceTag(0x62613371, ULSCat.msoulscat_WSS_Runtime, ULSTraceLevel.Medium, "Redirect to {0} failed. Exception: {1}", new object[] { url, exception2.ToString() });
        }
    }
    return flag;
}


internal static bool IsMDSEnabled(HttpContext ctx)
{
    return (((((ctx != null) && !DeltaPage.IsStartPage) && (!SPMobileUtility.IsMobilePageRequest(ctx, ctx.Request.Browser) && (ContextCompatibilityLevel >= 15))) && ((SPContext.Current != null) && (SPContext.Current.Web != null))) && SPContext.Current.Web.EnableMinimalDownload);
}


public static bool IsStartPage
{
    get
    {
        return IsMDSStartPageUrl(SPAlternateUrl.ContextUri.AbsolutePath);
    }
}


public static Uri ContextUri
{
    get
    {
        return GetContextUri(HttpContext.Current); //Here it throws an exception
    }
}

WORKING SOLUTION:

_currentContext.Response.Redirect

_currentContext.Response.Redirect does work though (IMPORTANT: Only when the form, which initiates an event, is being rendered in CSRRenderMode.ServerRender mode.) You can use the following sample:

public class TestEventHandler : SPItemEventReceiver
 {
  private readonly HttpContext _currentContext;
  public TestEventHandler()
  {
   _currentContext = HttpContext.Current;
  }
  // Methods
  public override void ItemAdding(SPItemEventProperties properties)
  {
   var url = new StringBuilder("test.aspx");
   string urlRedirect = null;
   bool flag = SPUtility.DetermineRedirectUrl(url.ToString(), SPRedirectFlags.RelativeToLayoutsPage, _currentContext, null, out urlRedirect);
   _currentContext.Response.Redirect(urlRedirect, true);
  }
 }

Wednesday, March 20, 2013

SharePoint 2013 CAML SPSiteDataQuery Lookup Field Bug

When using CAML and SPSiteDataQuery, and including a lookup field in ViewFields, you have to make sure this field is used in Query as well (i.e. in OrderBy). Otherwise it would not show up in your result dataset. This happens in SharePoint 2013 (15.0.4420.1017). Same query in 2010 and 2007 produces result dataset without the need to include the field in query. Looks like a bug in SharePoint 2013.

Wednesday, March 6, 2013

SharePoint 2013 Site Definition Migration

SharePoint 2013 site definition requires "<!-- _lcid="1033" _version="15.0.4420" _dal="1" -->" to be present in site definition template file (with respect to your regional settings obviously). It would not show up otherwise. It was not a requirement before, so make sure you have it updated/added when migrating your solution from 2007/2010.

Friday, February 8, 2013

Additional SharePoint 2013 App Part Tokens

There have been a very interesting article at SharePoint Developer Support Team Blog. It discusses editMode parameter, and also mentions WPID parameter in the code sample. This got me into researching this matter.

So far we had two MSDN articles, discussing tokens: URL strings and tokens in apps for SharePoint and URLs and tokens in SharePoint 2013.

They both lack a few important App Part tokens (parameters). Here they are:

  • editMode - has two possible values: 1 or 0. 1 means the web part (not Page) is currently in Edit Mode.
  • WPID - represents a WebPart.ID (sample value is "g_f5ac6d08_5b6f_41ea_90d1_0cc8a030061c").
  • WPQ - represents a WebPart.ClientID (sample value is "ctl00_ctl33_g_f4a94a49_ce63_4c7f_ba05_884b17132672").
  • WebLocaleId - represents a web.Language.ToString(CultureInfo.InvariantCulture) (sample value is "1033"), which is a Language Id.

You can use all those tokens in the URL, the same way as you use custom properties, without the need of adding actual properties. All tokens are case sensitive.

<ClientWebPart Name="ClientWebPart" Title="TestAppPart" Description="TestAppPart" DefaultWidth="600" DefaultHeight="300">
  
  <Content Type="html" Src="~appWebUrl/Pages/DemoPage.aspx?{StandardTokens}&amp;wpId=_WPID_&amp;editmode=_editMode_&amp;wpq=_WPQ_&amp;weblocaleId=_WebLocaleId_" />

  <Properties>
  </Properties>

</ClientWebPart>

There are a few additional tokens (parameters) not allowed for the app parts, but allowed when rendering XmlWebPart, PageViewerWebPart, ImageWebPart, DataViewWebPart and DataFormWebPart. I did not try them out though, so your feedback on their usage is welcome. Here they are:

  • LogonUser - represents a context.Request.ServerVariables["LOGON_USER"].
  • WPR - represents a Web Part Resource Path : (web.Url + "/" + web.TypeCache[type, web.IsAppWeb, false].WebRelativeClassResourcePath).
  • WPSRR - represents a Web Part Server Relative Resource Path : web.GetServerRelativeUrlFromUrl(web.TypeCache[type, web.IsAppWeb, false].WebRelativeClassResourcePath).

Wednesday, January 9, 2013

SharePoint SPSiteDataQuery DateTime Results Timezone

When working with SPSiteDataQuery keep in mind that all DateTime results are being returned either in current user profile regional settings timezone, or under root web regional settings timezone, depending on the settings. It will ignore all the sub web regional settings.

Wednesday, November 7, 2012

Anonymous Access and TaxonomyWebTaggingControl WebTaggingDialog

Trying to use TaxonomyWebTaggingControl with anonymous user? Control works fine, but the popup dialog (WebTaggingDialog). It will ask you for authentication no matter what. The reason is that it is an application page, which by default does not allow anonymous access.

So far I was able to find only one way to fix it, and it is described in Ironworks blog. You have to modify actual application page (WebTaggingDialog.aspx) located in LAYOUTS folder, by adding the following code:

<script runat="server" type="text/C#">
protected override bool AllowAnonymousAccess
{ 
    get
    { 
        return true; 
    } 
}
</script>

Please remember that this change is not supported by Microsoft and could be overridden during service pack deployment.

Thursday, November 1, 2012

SharePoint 20+ Items Lookup Positioning Issue

I was working with custom master page and stumbled on interesting problem, related to SharePoint lookup field with 20+ elements being rendered in IE in wrong place. There is plenty of information on how this control behaves (i.e. here), but not that much about how it actually works. I had to figure it out, in order to fix my problem, so hopefully this would help someone ;)Please read Boris Gomiunik's blog post before proceeding, cause it explains the basics of it.

When you click on the lookup field, the following script is called from core.js:

function ShowDropdown(textboxId)
{ULSsa6:;
 var ctrl=document.getElementById(textboxId);
 var str=ctrl.value;
 var opt=EnsureSelectElement(ctrl, ctrl.opt);
 ctrl.match=FilterChoice(opt, ctrl, "", ctrl.value);
 ctrl.focus();
}


function EnsureSelectElement(ctrl, strId)
{ULSsa6:;
 var select=document.getElementById(strId);
 if (select==null)
 {
  select=document.createElement("SELECT");
  ctrl.parentNode.appendChild(select);
  select.outerHTML="<select id=\""+strId+"\" ctrl=\""+ctrl.id+"\" class=\"ms-lookuptypeindropdown\" name=\""+strId+"\" style=\"display:none\" onfocusout=\"OptLoseFocus(this)\"></select>";
  FilterChoice(select, ctrl, ctrl.value, "");
 }
 return document.getElementById(strId);;
}

function FilterChoice(opt, ctrl, strVal, filterVal)
{ULSsa6:;
 var i;
 var cOpt=0;
 var bSelected=false;
 var strHtml="";
 var strId=opt.id;
 var strName=opt.name;
 var strMatch="";
 var strMatchVal="";
 var strOpts=ctrl.choices;
 var rgopt=strOpts.split("|");
 var x=AbsLeft(ctrl);
 var y=AbsTop(ctrl)+ctrl.offsetHeight;
 var elmWorkspace=document.getElementById("s4-workspace");
 if(elmWorkspace)
  y -=AbsTop(elmWorkspace);
 var strHidden=ctrl.optHid;
 var iMac=rgopt.length - 1;
 var iMatch=-1;
 var unlimitedLength=false;
 var strSelectedLower="";
 if (opt !=null && opt.selectedIndex >=0)
 {
  bSelected=true;
  strSelectedLower=opt.options[opt.selectedIndex].innerText;
 }
 for (i=0; i < rgopt.length; i=i+2)
 {
  var strOpt=rgopt[i];
  while (i < iMac - 1 && rgopt[i+1].length==0)
  {
   strOpt=strOpt+"|";
   i++;
   if (i < iMac - 1)
   {
    strOpt=strOpt+rgopt[i+1];
   }
   i++;
  }
  var strValue=rgopt[i+1];
  var strLowerOpt=strOpt.toLocaleLowerCase();
  var strLowerVal=strVal.toLocaleLowerCase();
  if (filterVal.length !=0)
   bSelected=true;
  if (strLowerOpt.indexOf(strLowerVal)==0)
  {
   var strLowerFilterVal=filterVal.toLocaleLowerCase();
   if ((strLowerFilterVal.length !=0) && (strLowerOpt.indexOf(strLowerFilterVal)==0) && (strMatch.length==0))
    bSelected=false;
   if (strLowerOpt.length > 20)
   {
    unlimitedLength=true;
   }
   if (!bSelected || strLowerOpt==strSelectedLower)
   {
    strHtml+="<option selected value=\""+strValue+"\">"+STSHtmlEncode(strOpt)+"</option>";
    bSelected=true;
    strMatch=strOpt;
    strMatchVal=strValue;
    iMatch=i;
   }
   else
   {
    strHtml+="<option value=\""+strValue+"\">"+STSHtmlEncode(strOpt)+"</option>";
   }
   cOpt++;
  }
 }
 var strHandler=" ondblclick=\"HandleOptDblClick()\" onkeydown=\"HandleOptKeyDown()\"";
 var strOptHtml="";
 if (unlimitedLength)
 {
  strOptHtml="<select tabIndex=\"-1\" ctrl=\""+ctrl.id+"\" name=\""+strName+"\" id=\""+strId+"\""+strHandler;
 }
 else
 {
  strOptHtml="<select class=\"ms-lookuptypeindropdown\" tabIndex=\"-1\" ctrl=\""+ctrl.id+"\" name=\""+strName+"\" id=\""+strId+"\""+strHandler;
 }
 if (cOpt==0)
 {
  strOptHtml+=" style=\"display:none;position:absolute;z-index:2;left:"+x+   "px;top:"+y+   "px\" onfocusout=\"OptLoseFocus(this)\"></select>";
 }
 else
 {
  strOptHtml+=" style=\"position:absolute;z-index:2;left:"+x+   "px;top:"+y+   "px\""+   " size=\""+(cOpt <=8 ? cOpt : 8)+"\""+   (cOpt==1 ? "multiple=\"true\"" : "")+   " onfocusout=\"OptLoseFocus(this)\">"+   strHtml+   "</select>";
 }
 opt.outerHTML=strOptHtml;
 var hid=document.getElementById(strHidden);
 if (iMatch !=0 || rgopt[1] !="0" )
  hid.value=strMatchVal;
 else
  hid.value="0";
 if (iMatch !=0 || rgopt[1] !="0" )
  return strMatch;
 else return "";
}

It is generating a new <select> element, and placing it right after the input box that you have clicked. It is setting its position as absolute, and calculating the left and top value from the start of the page. This is done using AbsLeft and AbsTop functions.

function AbsLeft(obj)
{ULSxSy:;
 var x=obj.offsetLeft;
 var parent=obj.offsetParent;
 while (parent !=null && parent.tagName !="BODY")
 {
  x+=parent.offsetLeft;
  parent=parent.offsetParent;
 }
 if (parent !=null)
  x+=parent.offsetLeft;
 return x;
}
function AbsTop(obj)
{ULSxSy:;
 var y=obj.offsetTop;
 var parent=obj.offsetParent;
 while (parent !=null && parent.tagName !="BODY")
 {
  y+=parent.offsetTop;
  parent=parent.offsetParent;
 }
 if (parent !=null)
  y+=parent.offsetTop;
 return y;
}

It sets an exact absolute calculated position for this element:

<SELECT 
style="Z-INDEX: 2; POSITION: absolute; DISPLAY: none; TOP: 436px; LEFT: 414px" onkeydown=HandleOptKeyDown() 
id=_Select 
onfocusout=OptLoseFocus(this) 
ondblclick=HandleOptDblClick() 
tabIndex=-1 
size=8 
name=_Select ctrl="ctl00_m_g_a0c896e4_02dd_41b4_87ea_58cdb333059b_ctl00_ctl05_ctl04_ctl00_ctl00_ctl04_ctl00_ctl01">

The problem is that if you have a div driven master page and have a div with the position:relative somewhere in between of the top of the page and select element, our select element is being placed relative to it, instead of relative to the top left corner of the page. If you have this problem, you need to find this element and override it to be "static".

Tuesday, June 14, 2011

LinkedIn Suspicious Activity

Being a fan of LinkedIn I am frequently checking who’s viewing my profile. Approximately half a year ago I have noticed weird activity out there. My profile is being viewed by numerous “Accounting Professionals” with 0 connections. I have a feeling that someone not affiliated with LinkedIn is gathering account information and account updates.

UPDATE (2011-06-16): Wow, they listened. ;) Half of those profiles now shows as Anonymous LinkedIn User. They have changed thir privacy settings.

To whom it may concern: If you are scanning through LinkedIn profiles it makes sence to use only one account for that. Otherwise it shows ugly in Profile Stats.

Please comment if you experience the same activity or have any additional information.

Here is the list of suspicious accounts hitting my profile for the last three month:

Hulda Virgile
Title: Accounting Professional
Demographic Info: Greater New York City Area | Accounting

Rico Natalizio
Title: Accounting Professional
Demographic Info: Greater New York City Area | Accounting

Zulema Miyares
Title: Accounting Professional
Demographic Info: Greater New York City Area | Accounting

Catheryn Rouw
Title: Accounting Professional
Demographic Info: Greater New York City Area | Accounting

Moshe Hinkle
Title: Accounting Professional
Demographic Info: Greater New York City Area | Accounting

Kendrick Corea
Title: Accounting Professional
Demographic Info: Greater New York City Area | Accounting

Leopoldo Avner
Title: Accounting Professional
Demographic Info: Greater New York City Area | Accounting

Ena Zenke
Title: Accounting Professional
Demographic Info: Greater New York City Area | Accounting

Charley Darner
Title: Accounting Professional
Demographic Info: Greater New York City Area | Accounting

Kellee Himelfarb
Title: Accounting Professional
Demographic Info: Greater New York City Area | Accounting

Alana Shannon
Title: Accounting Professional
Demographic Info: Greater New York City Area | Accounting

Julio Dyer
Title: Accounting Professional
Demographic Info: Greater New York City Area | Accounting

Francisco Head
Title: Accounting Professional
Demographic Info: Greater New York City Area | Accounting

Angelina Carroll
Title: Accounting Professional
Demographic Info: Greater New York City Area | Accounting

Stanley Justice
Title: Accounting Professional
Demographic Info: Greater New York City Area | Accounting

Isaac McCray
Title: Accounting Professional
Demographic Info: Greater New York City Area | Accounting

Chester Booth
Title: Accounting Professional
Demographic Info: Greater New York City Area | Accounting

Fernando Sanchez
Title: Accounting Professional
Demographic Info: Greater New York City Area | Accounting

Friday, April 22, 2011

How to use MOSS Publishing EditingMenuActions

Let’s say you want to use any of the Microsoft provided Publishing EditingMenuActions. There are a few dozens of them.

For example, you want to save page and switch it to the view mode. If you try something like the following – it will fail:

SwitchToPublishedModeAction action = new SwitchToPublishedModeAction();
action.RaisePostBackEvent("switchToPublished"); 

You have to specifically assign the Page for the action. The following code will work:

SwitchToPublishedModeAction action = new SwitchToPublishedModeAction();
action.Page = this.Page;
action.RaisePostBackEvent("switchToPublished"); 

Any ConsoleAction is essentially a WebControl. It should either be placed on the page itself, and then referenced in your code, or you can just set its Page property.

Here is the list of actions accessible from Microsoft.SharePoint.Publishing.WebControls.EditingMenuActions namespace:

  • public sealed class ApproveAction : BaseApproveAction
  • public sealed class ApproveOrDeclineAction : ConsoleAction
  • public abstract class BaseApproveAction : ConsoleAction
  • public abstract class BaseDeclineAction : ConsoleAction
  • public sealed class BrowseWebPartsAction : ConsoleAction
  • public sealed class CancelApprovalRequestAction : ConsoleAction
  • public sealed class CancelApprovalWorkflowRequestAction : ConsoleAction
  • public sealed class CancelSchedulingAction : ConsoleAction
  • public sealed class CheckInAction : ConsoleAction
  • public sealed class CheckInWithCommentAction : ConsoleAction
  • public sealed class CheckOutAction : ConsoleAction
  • public sealed class CheckOutOverrideAction : ConsoleAction
  • public sealed class CopyAction : ConsoleAction
  • public sealed class CreateNewPublishingPageAction : ConsoleAction
  • public sealed class CreateNewSiteAction : ConsoleAction
  • public sealed class CreateNewsLinkAction : ConsoleAction
  • public sealed class CreatePageVariationAction : ConsoleAction
  • public sealed class CreateSiteVariationAction : ConsoleAction
  • public sealed class DeclineAction : BaseDeclineAction
  • public sealed class DeleteAction : ConsoleAction
  • public sealed class EditListItemPropertiesAction : ConsoleAction
  • public sealed class EditPropertiesAction : ConsoleAction
  • public sealed class ExitMenuAction : ConsoleAction
  • public sealed class ExitWithoutSavingAction : ConsoleAction
  • public sealed class ForceSavePublishingPageAction : ConsoleAction
  • public sealed class ImportWebPartsAction : ConsoleAction
  • public sealed class ManageSiteAction : ConsoleAction
  • public sealed class ModifyNavigationAction : ConsoleAction
  • public sealed class ModifyPagesLibrarySettingsAction : ConsoleAction
  • public sealed class ModifyWebPartsNode : ConsoleNode
  • public sealed class MoveAction : ConsoleAction
  • public sealed class OneClickPublishAction : ConsoleAction
  • public sealed class PersonalViewAction : ConsoleAction
  • public sealed class PreviewAction : ConsoleAction
  • public sealed class PreviewExistingPublishingPageAction : ConsoleAction
  • public sealed class PublishAction : ConsoleAction
  • public sealed class PublishWithCommentAction : ConsoleAction
  • public sealed class QuickDeployAction : ConsoleAction
  • public sealed class ReportsNode : ConsoleNode
  • public sealed class ReviewPublishingPageAction : ConsoleAction
  • public sealed class RevisionHistoryAction : ConsoleAction
  • public sealed class SavePublishingPageAction : ConsoleAction
  • public sealed class SearchWebPartsAction : ConsoleAction
  • public sealed class SharedViewAction : ConsoleAction
  • public sealed class ShowUnapprovedResourcesAction : ConsoleAction
  • public sealed class SiteDirectoryBrokenLinksCheckerAction : ConsoleAction
  • public sealed class SiteSettingsAction : ConsoleAction
  • public sealed class SpellCheckEntirePageAction : ConsoleAction
  • public sealed class SwitchToAuthoringModeAction : ConsoleAction
  • public sealed class SwitchToPublishedModeAction : ConsoleAction
  • public sealed class UndoCheckOutAction : ConsoleAction
  • public sealed class UnpublishAction : ConsoleAction
  • public sealed class UpdateVariationsAction : ConsoleAction
  • public sealed class VersionDifferenceAction : ConsoleAction
  • public sealed class VersionInfoAction : ConsoleAction
  • public sealed class ViewAllSiteContentAction : ConsoleAction
  • public sealed class ViewRecycleBinAction : ConsoleAction
  • public sealed class WorkflowApproveAction : BaseApproveAction
  • public sealed class WorkflowDeclineAction : BaseDeclineAction
  • public sealed class WorkflowStartAction : ConsoleAction
  • public sealed class WorkflowStatusAction : ConsoleAction
  • public sealed class WorkflowTasksAction : ConsoleAction

Wednesday, March 2, 2011

Enabling WCF support in SharePoint 2007 on Windows 2008 R2 IIS7

Installing SharePoint 2007 on Windows Server 2008 R2 sets SharePoint IIS application pools to Classic mode. In context of WCF this means that you have to manually configure WCF support in Web Applications web.configs. Otherwise you will get 404 errors trying to access any .svc files in your application.

In order to enable WCF support to SharePoint 2007 installed on Windows Server 2008 R2 with IIS 7.5, you have to put the following records to the web.config:

<system.webServer>
<handlers>
<add name="svc-ISAPI-2.0" path="*.svc" verb="*" modules="IsapiModule" scriptProcessor="%SystemRoot%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" />
<add name="svc-ISAPI-2.0-64" path="*.svc" verb="*" modules="IsapiModule" scriptProcessor="%SystemRoot%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" />
</handlers>
</system.webServer>

P.S.: It is probably the case with any web application runing in classic mode in IIS7.

Wednesday, November 3, 2010

Windows Media Services and Silverlight Media Framework

While Windows Media Services is being supported by Silverlight Media Framework, server-side playlists support is limited. It is not possible to use fast forward and scroll through the video while using server-side playlists (WSX). Based on Microsoft these features are not going to be supported anytime soon.

Wednesday, March 17, 2010

Excel Services, ODC and Microsoft.ACE.OLEDB.14.0

Please check latest updates at the end of the article.

In my previous post I was talking about new 2010 Office Data Connectivity Components, or Microsoft.ACE.OLEDB.14.0. I have a small sample there how to programmatically access SharePoint 2007 data using this component. While this approach works great when you are building any custom solution, there is also a way to use these components without any coding at all.

Microsoft.ACE.OLEDB.14.0 can be used in Excel Services, working around its limitation on SharePoint data sources. For instance this could be used to create Excel Charts and Pivot tables, based on SharePoint data source.

This solution tested on SharePoint 2007 Server (MOSS) and Microsoft Office 2007.

Prerequisites:

  • You will need 2010 Office Data Connectivity Components installed on your SharePoint 2007 / Excel Services machine.
  • Do not forget to go to Central Admin -> Shared Services -> Trusted Data Providers -> add it up there as Provider ID = "Microsoft.ACE.OLEDB.12.0" and Provider Type = "OLE DB".
  • You need to have Excel Services Trusted Location (defined in Central Admin)

We can't use Microsoft.ACE.OLEDB.14.0 directly from Excel, data connection wizard will fail to create Data Link. But we still can create our own Office Data Connection (ODC) file.

Instead of "Provider=Microsoft.ACE.OLEDB.14.0" we have to use "Provider=Microsoft.ACE.OLEDB.12.0". It's a bug and would be probably fixed in release.

Here is the source XML for the sample ODC file. Copy it to your favorite text editor and change <odc:ConnectionString>:

  • User ID - not relevant
  • Data Source - url to your SharePoint site
  • DATABASE - url to your SharePoint site
  • LIST - List Title (not Name) or List GUID
  • There is no need to change [List] in <odc:CommandText> - it will load data from the list, referenced in LIST anyway
<html xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns="http://www.w3.org/TR/REC-html40">

<head>
<meta http-equiv=Content-Type content="text/x-ms-odc; charset=utf-8">
<meta name=ProgId content=ODC.Table>
<meta name=SourceType content=OLEDB>
<title>(Default)</title>
<xml id=docprops><o:DocumentProperties
  xmlns:o="urn:schemas-microsoft-com:office:office"
  xmlns="http://www.w3.org/TR/REC-html40">
  <o:Name>(Default)</o:Name>
 </o:DocumentProperties>
</xml><xml id=msodc><odc:OfficeDataConnection
  xmlns:odc="urn:schemas-microsoft-com:office:odc"
  xmlns="http://www.w3.org/TR/REC-html40">
  <odc:Connection odc:Type="OLEDB">
   <odc:ConnectionString>Provider=Microsoft.ACE.OLEDB.12.0;User ID=Admin;Data Source=http://moss.sharepointalist.com/SiteDirectory/ACETest;Mode=Share Deny None;Extended Properties=&quot;WSS;HDR=No;IMEX=0;DATABASE=http://moss.sharepointalist.com/SiteDirectory/ACETest;LIST=List Title;RetrieveIDs=Yes&quot;;Jet OLEDB:System database=&quot;&quot;;Jet OLEDB:Registry Path=&quot;&quot;;Jet OLEDB:Engine Type=0;Jet OLEDB:Database Locking Mode=0;Jet OLEDB:Global Partial Bulk Ops=2;Jet OLEDB:Global Bulk Transactions=1;Jet OLEDB:New Database Password=&quot;&quot;;Jet OLEDB:Create System Database=False;Jet OLEDB:Encrypt Database=False;Jet OLEDB:Don't Copy Locale on Compact=False;Jet OLEDB:Compact Without Replica Repair=False;Jet OLEDB:SFP=False;Jet OLEDB:Support Complex Data=False</odc:ConnectionString>
   <odc:CommandType>SQL</odc:CommandType>
   <odc:CommandText>SELECT * FROM [List]</odc:CommandText>
   <odc:AlwaysUseConnectionFile/>
  </odc:Connection>
 </odc:OfficeDataConnection>
</xml>
<style>
<!--
    .ODCDataSource
    {
    behavior: url(dataconn.htc);
    }
-->
</style>
 
</head>

<body onload='init()' scroll=no leftmargin=0 topmargin=0 rightmargin=0 style='border: 0px'>
<table style='border: solid 1px threedface; height: 100%; width: 100%' cellpadding=0 cellspacing=0 width='100%'> 
  <tr> 
    <td id=tdName style='font-family:arial; font-size:medium; padding: 3px; background-color: threedface'> 
        
    </td> 
     <td id=tdTableDropdown style='padding: 3px; background-color: threedface; vertical-align: top; padding-bottom: 3px'>

        
    </td> 
  </tr> 
  <tr> 
    <td id=tdDesc colspan='2' style='border-bottom: 1px threedshadow solid; font-family: Arial; font-size: 1pt; padding: 2px; background-color: threedface'>

        
    </td> 
  </tr> 
  <tr> 
    <td colspan='2' style='height: 100%; padding-bottom: 4px; border-top: 1px threedhighlight solid;'> 
      <div id='pt' style='height: 100%' class='ODCDataSource'></div> 
    </td> 
  </tr> 
</table> 

  
<script language='javascript'> 

function init() { 
  var sName, sDescription; 
  var i, j; 
  
  try { 
    sName = unescape(location.href) 
  
    i = sName.lastIndexOf(".") 
    if (i>=0) { sName = sName.substring(1, i); } 
  
    i = sName.lastIndexOf("/") 
    if (i>=0) { sName = sName.substring(i+1, sName.length); } 

    document.title = sName; 
    document.getElementById("tdName").innerText = sName; 

    sDescription = document.getElementById("docprops").innerHTML; 
  
    i = sDescription.indexOf("escription>") 
    if (i>=0) { j = sDescription.indexOf("escription>", i + 11); } 

    if (i>=0 && j >= 0) { 
      j = sDescription.lastIndexOf("</", j); 

      if (j>=0) { 
          sDescription = sDescription.substring(i+11, j); 
        if (sDescription != "") { 
            document.getElementById("tdDesc").style.fontSize="x-small"; 
          document.getElementById("tdDesc").innerHTML = sDescription; 
          } 
        } 
      } 
    } 
  catch(e) { 

    } 
  } 
</script> 

</body> 
 
</html>

  • Save file with .odc extension and try opening it in Microsoft Excel. If everything is right, you should get your data loaded in Excel.
  • Save your .odc file in Data Connection Library in SharePoint 2007 (MOSS). Approve it, or ask owner of the site (administrator) to approve it. It will still work for you without the approval, but not for the other users.
  • Create a new Excel Workbook, under Insert tab select PivotChart (or PivotTable).
  • In the "Create PivotTable with PivotChart" dialog select "Use an external data source" and click on "Choose connection button".
  • Click "Browse for more" and navigate to your .odc file in SharePoint Data Connection Library.
  • Build up your Pivot Chart or Pivot Table.
  • When you are done, click on Office Button and select Publish -> Excel Services.
  • Browse to your target SharePoint document library.
  • Click "Excel Services Options" button and select what items do you want to publish using Excel Services.
  • Save the file. Now you should be able to access your pivot table or pivot chart using Excel Web Access Web Part. That charts/table are totally dynamic and will show your updated data when refreshed.

Update (05/07/2010):

After some additional research and help from Ivan Huter looks like described method works with standalone MOSS installation only. You will have to configure Kerberos Authentification in order to make it working in a farm. Unfortunately I do not have time right now to test Kerberos option, but I will post an update when I get a chance.

Let me know if you have any questions or notes.

Friday, February 12, 2010

2010 Office Data Connectivity Components

Recently I was creating SharePoint Designer Workflow Activity to import data from Excel. Traditionally I used OLEDB to do that, but my target platform was 64bit and I could not use 2007 OLEDB Drivers (64 bit drivers version has never been implemented). Fortunately Microsoft released 2010 Office System Driver Beta: Data Connectivity Components at the end of 2009. This driver works fine, but instead of "Provider=Microsoft.ACE.OLEDB.14.0" you still have to access it using "Provider=Microsoft.ACE.OLEDB.12.0" and "Extended Properties='Excel 12.0 Xml'". This would be probably fixed in release.

This driver also not always detecting last filled row in Excel, so make sure you are handling that.

Do not forget to go to Central Admin -> Shared Services -> Trusted Data Providers -> add it up there as Provider ID = "Microsoft.ACE.OLEDB.12.0" and Provider Type = "OLE DB".

Here is some sample code to help to work with it:


                            string sConnectionString = "";
                            string FileType = "";
                            switch (Path.GetExtension(sourceItem.File.ServerRelativeUrl))
                            {
                                case ".xlsx":
                                    FileType = "Excel 12.0 Xml;";
                                    break;
                                case ".xlsm":
                                    FileType = "Excel 12.0 Macro;";
                                    break;
                                case ".xlsb":
                                    FileType = "Excel 12.0;";
                                    break;
                                default:
                                    FileType = "Excel 12.0;";
                                    break;
                            }

                            sConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;" + "Data Source=" + tempFile + ";" + "Extended Properties=\"" + FileType + "HDR=No;IMEX=0;\"";
                            OleDbConnection objConn = new OleDbConnection(sConnectionString);
                            objConn.Open();

                            OleDbDataReader dr = new OleDbCommand("SELECT * FROM [" + this.WorksheetName + "$]", objConn).ExecuteReader();

                            for (int i = 1; i <= RowStart; i++)
                            {
                                dr.Read();
                            }

                            while (dr.Read())
                            {
                                //Put your logic here
                            }
                            objConn.Close();

Monday, November 23, 2009

Installing SharePoint 2010 on machine with existing SQL Server 2008

If you already have SQL Server 2008 installed, DO NOT install SharePoint 2010 as a single server (standalone) version. It will create additional instance of SQL Server Express, which is obviously not what you want. This also brings some additional problems (based on this). Select a full installation. If you don't have domain and using local accounts - you need to read this blog.

Thursday, November 19, 2009

SharePoint 2010 Beta Installation

Do not try installing SharePoint 2010 Beta (14.0.4536.1000) on top of SharePoint 2010 Technical Preview (14.0.4006.1010) unless you really need this.It will install but would not work correctly. Just uninstall previous version first.

Office 2010 x64 with Office 2003/2007 side by side

I am still using Office 2003 to be able to work with some legacy applications. While installing Beta Office 2010 x64 I got an error that I can't use 2003 and 2007 side by side with 2010 x64 - and I have to use x86 instead.

Just uninstall all 2003/2007 office apps, install 2010 x64 and than install office 2003/2007 without any problems.

Tuesday, October 13, 2009

Invalid Canary for view file

After we installed Infrastructure Updates we started to experience some problems with InfoPath Forms - getting "There has been an error while loading the form. A required resource could not be downloaded. To try to resume the download, refresh the page.", when using some of the alternative URLs.

SharePoint logs was showing me "WARNING: Invalid Canary for view file"

Based on the info from the Microsoft, there is an known problem with the Alternate Access Mapping in Infrastructure Updates. The next cumulative update is supposed to fix this issue. Will update this post as soon as I get it installed and verified.



Update: After installing SP2 issue was fixed.

InfoPath property promotion (field association) problem

Just experienced the following problem today - spend a couple hours on figuring it out: I have a full-trusted infoPath form that is allready published and working. There were a few form properties/fields associated with the fields/columns in the SharePoint. I have tried adding a few additional - but it didn't work. The fields were there, the values were inside of the InfoPath form, but they were not carried over to SharePoint. It looks like you need to reactivate (deactivate first and activate again) this form for the site collection from the Central Admin in order for those associations to be refreshed.

Monday, August 24, 2009

InfoPath 2007 Bug - Form Does not Submit

Encountered weird InfoPath bug. Had an Approval Workflow with the InfoPath 2007 Web Form (MOSS). User had problems submitting the Form, click on the submit button was doing nothing. Reopening the Form was enough to submit. I watched how user worked with the Form, and noticed that the user was double clicking on the email link, which was causing the form to load twice (in two IE tabs). Changing this habit to clicking only once - solved the problem completely.

I have no idea why double loading the form was preventing it from submitting, but that's what it was.

Friday, May 29, 2009

SSRS Column Width Auto Size

While fixing the problem described in my previous post I saw lots of people trying to set auto width for the columns. Without any luck though... I have found a way:

  1. Change Expression to be something like =”<DIV>” & Replace(Fields!YourField.Value," ","&nbsp;") & “</DIV>”
  2. Change placeholder properties – General tab – Markup type – HTML-Interpret HTML tags as styles. (Placeholder properties can be accessed by right clicking on Expression (Field) inside of the cell, not on cell itself).

That was too easy :)

PS. Works for SSRS 2008, never tested on 2005.

PPS. Keep in mind - this works ONLY in web browser. Export to PDF and even printing will still use predesigned column width. There might be a workaround too - but I don't really need it, so I will leave it to you guys.

Please comment if you find any additional notes.

Wednesday, May 27, 2009

SSRS Column Width Long Text Problem

Recently I got a weird problem building some reports with SSRS 2008. The column width started to automatically resize based on content, while all columns width are fixed in SSRS by design. The cause of this was long words and long URLs in these fields, which were not able to wrap. Looks like HTML table was adjusting the column size accordingly. (By the way, it was still showing Ok in preview, but was changing the size of columns in published version.) Spent quite a time trying to figure out what to do with that, cause I need those column widths to be static. Here is the solution:

While this problem is caused by native HTML functionality, we can use HTML to fix it.

  1. Change Expression to be something like =”<DIV style=’width:1.2in’>” & Fields!YourField.Value & “</DIV>” where width is the desired static width of this column.
  2. Change placeholder properties – General tab – Markup type – HTML-Interpret HTML tags as styles. (Placeholder properties can be accessed by right clicking on Expression (Field) inside of the cell, not on cell itself).

PS. I am also sure that you can use the same approach to create columns with adjustable or auto width, it just needs some tweaking. Update: Here it is.

Monday, April 13, 2009

JavaScript in SharePoint 2007 / MOSS Data View XSL

This sound obvious, but looks like lots of people do not know this. YES, you can use JavaScript in XSL. And YES, you can use JavaScript in SharePoint Data View XSL. And it is fairly easy. Here is a small sample.

Let’s say we want to know how old each item we view in Data View is. As the version of XSL used in SharePoint is “1.0”, we don’t really have a wide scope of date functions. Actually we do have only “FormatDate” function, and even this one comes from a special (ddwrt) Microsoft namespace.

Anyhow, instead of working with XSL, trying to create some crazy Template to handle this task, we can simply use JavaScript.

I assume here that you worked with SharePoint Designer 2007 and Data Views before.

You’ll have to add a JavaScript function first. You can add/link it to the page, page layout or master page, does not matter. I will use slightly modified script from “The JavaScript Source”.

<script type="text/javascript">
 var montharray=new Array("Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec");
 function countup(dat) {
  var dt = new Date(Date.parse(dat));
  var yr =dt.getYear();
  var m =dt.getMonth();
  var d =dt.getDate();
  var today=new Date();
  var todayy=today.getYear();
  if ((navigator.appName=="Microsoft Internet Explorer") && (todayy<2000))
   todayy="19"+todayy;
  if (navigator.appName == "Netscape")
   todayy=1900 + todayy;
  var todaym=today.getMonth();
  var todayd=today.getDate();
  var todaystring=montharray[todaym]+" "+todayd+", "+todayy;
  var paststring=montharray[m]+" "+d+", "+yr;
  var difference=(Math.round((Date.parse(todaystring)-Date.parse(paststring))/(24*60*60*1000))*1);
  document.write(difference + " day(s)");
 }
</script>

Now we need to call this JavaScript function from Data View. Just click into one of the respectful cells in your Data View, and switch to Code View. You’ll see something like this:

<td class="ms-vb">
 <xsl:value-of select="ddwrt:FormatDate(string(@Modified), 1033, 5)" />
</td>

Now we’ll edit it, adding the JavaScript Call:

<td class="ms-vb">
 <script language="javascript">countup("<xsl:value-of select="ddwrt:FormatDate(string(@Modified),1033,1)" />");</script>
</td>

Vuala!


PS: I did not add any screen shots here assuming that it is fairly easy, but if you need some, just leave some comments.

SharePoint 2007 / MOSS URL Zones are limited

Ever wondered if there is any way to add additional zone to the list of URL Zones in SharePoint Central Administration? Sorry guys, no way. It is actually a predefined enumeration defined in Microsoft.SharePoint.dll

public enum SPUrlZone
{
    Default,
    Intranet,
    Internet,
    Custom,
    Extranet
}

Sunday, April 12, 2009

SharePoint 2007 / MOSS Page Refers Old Layout

Recently I was working a lot with SharePoint 2007 / MOSS Publishing Pages and Layouts. I noticed a weird behavior when I was moving some of the pages from dev environment to production. Sometimes the link to page layout is getting stuck and still pointing to an old (dev) environment. It was not obvious to find a way to fix it…

First I tried just exporting those pages to my local disk and editing it in notepad and putting it back. This approach did work, but was a little bit too manual…

After some head scratching I finally found a Page Settings page. When your page editing toolbar is visible (you clicked on “Site Actions” ->“Edit Page”), you can click on Page dropdown and select “Page Settings and Schedule”. On that page you can control Page Title and Description, Publishing Schedule, Page Layout, Audience Targeting and Page Contact. Alternatively you can just browse to it http://your-sharepoint-site/_layouts/PageSettings.aspx?Page=<Page ID>.

I had a few situations when it was still not working, and I was getting an error trying to change layout settings. You can always edit it in notepad in that case, as I described earlier.

Wednesday, April 8, 2009

Thicket “_files” folder and SharePoint 2007 (MOSS)

I got into this one when I was asked to put some Microsoft Publisher generated files into SharePoint 2007 site. Basically I got “index.html” file and “index_files” folder with some images and html files inside. I did put the index file into the root, then created the Document Library named “index_files”. Also I uploaded all the files into it without any problems using “Open in Windows Explorer” functionality. Everything actually started to work well. Then I was surprised that I don’t see this document library in SharePoint Designer. When I opened it from the browser – it was empty. But it was still showing all the files when opened with Windows Explorer. When I tried to change document library settings to work with content types, the whole settings page started to throw error.

I did some research and it looks like SharePoint 2007 has some native support of so called “thicket” folder (“_files” folder). SharePoint does not allow creating such a folder when you don’t have a corresponding (parent) file. When you try to create such folder using SharePoint Designer, it appends its name with an underscore at the end. SharePoint web interface hides content of such folder, while keeping those files accessible from Windows Explorer or when you browse/refer it directly.

My advise – try to avoid thickets in SharePoint. Those are hard to manage there.

Tuesday, March 24, 2009

"SharePoint designer encountered an error generating the task form" error caused by using IP address instead of machine name

Never use IP address instead of machine name while using SharePoint Designer. You can save yourself some time NOT trying to solve the problems caused by that…

I was playing with some SharePoint Designer workflows the other day and was getting “SharePoint designer encountered an error generating the task form” error all the time. And yes, the moment I changed IP to machine name, the problem was gone. And that is not the first error in my practice I had because of that issue.

Tuesday, March 10, 2009

Creating and customizing SharePoint 2007/MOSS Central Administration Application Pages

Some time ago I got a task create my own SharePoint Central Admin Page. I did start googling and going through different blogs but found almost nothing. Some tips here and there and that’s pretty much it. When I was finally done, I decided that I should structure all my experience whenever I get a chance. So, finally, half a year later I decided to start this blog with this article.

A brief introduction

SharePoint Central Admin Pages physically located inside \12\Admin folder. If you want to look through how some of the current Central Admin Application Pages function, you may use .NET Reflector on Microsoft.Sharepoint.ApplicationPages.Administration.dll and Microsoft.Office.Server.UI.dll. It is respectively located inside of \12\CONFIG\ADMINBIN folder and Assembly Cache.

Review out-of-the-box pages.

Lets review existing MOSS out-of-the-box Central Administration Application Pages:
PageInheritsBased
Operations
Operations.aspxMicrosoft.SharePoint.ApplicationPages.OperationsLandingPageGlobalAdminPageBase
FarmServers.aspxMicrosoft.SharePoint.ApplicationPages.FarmServersPageOperationsPage : GlobalAdminPageBase
Server.aspxMicrosoft.SharePoint.ApplicationPages.ServerPageOperationsPage : GlobalAdminPageBase
GlobalEmailConfig.aspxMicrosoft.SharePoint.ApplicationPages.GlobalEmailConfigPageOperationsPage : GlobalAdminPageBase
IncomingEmail.aspxMicrosoft.SharePoint.ApplicationPages.IncomingEmailPageOperationsPage : GlobalAdminPageBase
FarmCredentialManagement.aspxMicrosoft.SharePoint.ApplicationPages.FarmCredentialManagementPageOperationsPage : GlobalAdminPageBase
irmadmin.aspxMicrosoft.SharePoint.ApplicationPages.IrmGlobalSettingsOperationsPage : GlobalAdminPageBase
avadmin.aspxMicrosoft.SharePoint.ApplicationPages.AntiVirusConfigPageOperationsPage : GlobalAdminPageBase
BlockedFileType.aspxMicrosoft.SharePoint.ApplicationPages.BlockedFileTypePageOperationsPage : GlobalAdminPageBase
policyfeatures.aspxMicrosoft.Office.RecordsManagement.InformationPolicy. ApplicationPages.PolicyFeatures (Microsoft.Office.Policy.AdminPages.dll)GlobalAdminPageBase
managesso.aspxMicrosoft.SharePoint.Portal.SingleSignonAdministration.ManageSSOPage (Microsoft.SharePoint.Portal.dll)SSOAdminBase : OfficeServerPageBase
metrics.aspxMicrosoft.SharePoint.ApplicationPages.MetricsPageOperationsPage : GlobalAdminPageBase
LogUsage.aspxMicrosoft.SharePoint.ApplicationPages.LogUsagePageOperationsPage : GlobalAdminPageBase
policyRptConfig.aspxMicrosoft.Office.RecordsManagement.Reporting. ApplicationPages.PolicyRptConfig (Microsoft.Office.Policy.AdminPages.dll)GlobalAdminPageBase
CMSMigration.aspxMicrosoft.SharePoint.Publishing.Internal.CodeBehind.ManageMigrationProfile (Microsoft.Sharepoint.Publishing.dll)Microsoft.SharePoint.WebControls. UnsecuredLayoutsPageBase
SkuUpgrade.aspxMicrosoft.SharePoint.Portal.ServerAdmin.SkuUpgradePage(Microsoft.SharePoint.Portal.dll)CentralAdminPageBase
EnableFeatures.aspxMicrosoft.SharePoint.Portal.ServerAdmin.FeaturePushdownPage (Microsoft.SharePoint.Portal.dll)CentralAdminPageBase
Conversion.aspxMicrosoft.Office.Server.Internal.UI.ConversionPageCentralAdminPageBase
ServiceRunningJobs.aspxMicrosoft.SharePoint.ApplicationPages.TimerJobsPageOperationsPage : GlobalAdminPageBase
ServiceJobDefinitions.aspxMicrosoft.SharePoint.ApplicationPages.TimerJobsPageOperationsPage : GlobalAdminPageBase
sitedirectorysettings.aspxMicrosoft.SharePoint.Portal.ServerAdmin.SiteDirectorySettings (Microsoft.SharePoint.Portal.dll)CentralAdminPageBase
linkscheckerjobsettings.aspxMicrosoft.SharePoint.Portal.SiteAdmin.LinksCheckerJobSettings (Microsoft.SharePoint.Portal.dll)CentralAdminPageBase
AlternateUrlCollections.aspxMicrosoft.SharePoint.ApplicationPages.AlternateUrlCollectionsPageGlobalAdminPageBase
ManageFarmFeatures.aspxMicrosoft.SharePoint.ApplicationPages.ManageFarmFeaturesPageApplicationsManagementPage : GlobalAdminPageBase
QuiesceFarm.aspxMicrosoft.Office.Server.Internal.UI.QuiesceFarmPageCentralAdminPageBase
Solutions.aspxMicrosoft.SharePoint.ApplicationPages.OperationsPageGlobalAdminPageBase
backup.aspxMicrosoft.SharePoint.ApplicationPages.BackupPageBackupAdminPageBase : OperationsPage : GlobalAdminPageBase
backuphistory.aspxMicrosoft.SharePoint.ApplicationPages.BackupHistoryPageBackupAdminPageBase : OperationsPage : GlobalAdminPageBase
restorestep1.aspxMicrosoft.SharePoint.ApplicationPages.RestoreStep1PageBackupAdminPageBase : OperationsPage : GlobalAdminPageBase
Restorestep3.aspxMicrosoft.SharePoint.ApplicationPages.RestoreStep3PageBackupAdminPageBase : OperationsPage : GlobalAdminPageBase
backupstatus.aspxMicrosoft.SharePoint.ApplicationPages.BackupStatusPageBackupAdminPageBase : OperationsPage : GlobalAdminPageBase
defaultcontentdb.aspxMicrosoft.SharePoint.ApplicationPages.DefaultContentDatabasePageOperationsPage : GlobalAdminPageBase
DspSettings.aspxMicrosoft.SharePoint.ApplicationPages.DspSettingsOperationsPage : GlobalAdminPageBase
Deployment.aspxMicrosoft.SharePoint.Publishing.Internal.CodeBehind. DeployManagePathsAndJobsPage (Microsoft.Sharepoint.Publishing.dll)BasePublishingPage : LayoutsPageBase : UnsecuredLayoutsPageBase
DeploymentSettings.aspxMicrosoft.SharePoint.Publishing.Internal.CodeBehind.DeploySettingsPage (Microsoft.Sharepoint.Publishing.dll)BasePublishingPage : LayoutsPageBase : UnsecuredLayoutsPageBase
DeploymentStatus.aspxMicrosoft.SharePoint.Publishing.Internal. CodeBehind.DeploymentObjectStatusPage (Microsoft.Sharepoint.Publishing.dll)BasePublishingPage : LayoutsPageBase : UnsecuredLayoutsPageBase
Application Management
applications.aspxMicrosoft.SharePoint.ApplicationPages.ApplicationsPageGlobalAdminPageBase
extendvsoption.aspxMicrosoft.SharePoint.ApplicationPages.ExtendVsOptionPageGlobalAdminPageBase
unextendvs.aspxMicrosoft.SharePoint.ApplicationPages.UnextendVirtualServerPageApplicationsManagementPage : GlobalAdminPageBase
deletewebapplication.aspxMicrosoft.SharePoint.ApplicationPages.DeleteWebApplicationPageApplicationsManagementPage : GlobalAdminPageBase
scprefix.aspxMicrosoft.SharePoint.ApplicationPages.SscPrefixPageApplicationsManagementPage : GlobalAdminPageBase
vsemail.aspxMicrosoft.SharePoint.ApplicationPages.VSEmailConfigPageApplicationsManagementPage : GlobalAdminPageBase
vsgeneralsettings.aspxMicrosoft.SharePoint.ApplicationPages.VirtualServerGeneralSettingsPageApplicationsManagementPage : GlobalAdminPageBase
cntdbadm.aspxMicrosoft.SharePoint.ApplicationPages.ContentDBManagmentPageApplicationsManagementPage : GlobalAdminPageBase
ManageWebAppFeatures.aspxMicrosoft.SharePoint.ApplicationPages.ManageWebAppFeaturesPageApplicationsManagementPage : GlobalAdminPageBase
WebApplications.aspxMicrosoft.SharePoint.ApplicationPages.ListWebApplicationsPageSelectWebApplicationPage : SelectPage : GlobalAdminPageBase
managessp.aspxMicrosoft.Office.Server.Internal.UI.ManageSspPageCentralAdminPageBase
manageinterfarmservices.aspxMicrosoft.Office.Server.Internal.UI.ManageInterFarmServicesPageCentralAdminPageBase
checkfarmservices.aspxMicrosoft.Office.Server.Internal.UI.CheckFarmServicesPageCentralAdminPageBase
SessionStateAdmin.aspxMicrosoft.Office.Server.Internal.UI.SessionStateAdminPageCentralAdminPageBase
SPSecuritySettings.aspxMicrosoft.SharePoint.ApplicationPages.WebPartPageSettingsPageApplicationsManagementPage : GlobalAdminPageBase
configssc.aspxMicrosoft.SharePoint.ApplicationPages.ConfigSscPageApplicationsManagementPage : GlobalAdminPageBase
vsmask.aspxMicrosoft.SharePoint.ApplicationPages.VirtualServerMaskPageApplicationsManagementPage : GlobalAdminPageBase
policy.aspxMicrosoft.SharePoint.ApplicationPages.PolicyPageApplicationsManagementPage : GlobalAdminPageBase
AuthenticationProviders.aspxMicrosoft.SharePoint.ApplicationPages.GlobalAdminPageBase
managesearchservice.aspxMicrosoft.SharePoint.Portal.Search.Admin.Pages.ManageSearchService (Microsoft.SharePoint.Portal.dll)SearchCentralAdminPageBase : CentralAdminPageBase
workflowadmin.aspxMicrosoft.SharePoint.ApplicationPages.WorkflowAdminPageApplicationsManagementPage : GlobalAdminPageBase
createsite.aspxMicrosoft.SharePoint.ApplicationPages.CreateSitePageApplicationsManagementPage : GlobalAdminPageBase
delsite.aspxMicrosoft.SharePoint.ApplicationPages.DeleteSitePageApplicationsManagementPage : GlobalAdminPageBase
DeleteSiteConfig.aspxMicrosoft.SharePoint.ApplicationPages.DeleteSiteConfigApplicationsManagementPage : GlobalAdminPageBase
ManageQuotaTemplate.aspxMicrosoft.SharePoint.ApplicationPages.ManageQuotaTemplatePageApplicationsManagementPage : GlobalAdminPageBase
SiteQuota.aspxMicrosoft.SharePoint.ApplicationPages.SiteQuotaPageApplicationsManagementPage : GlobalAdminPageBase
owners.aspxMicrosoft.SharePoint.ApplicationPages.OwnersPageApplicationsManagementPage : GlobalAdminPageBase
SiteCollections.aspxMicrosoft.SharePoint.ApplicationPages.ListSitesPageSelectSitePage : SelectPage : GlobalAdminPageBase
OfficialFileAdmin.aspxMicrosoft.SharePoint.ApplicationPages.OfficialFileAdminPageApplicationsManagementPage : GlobalAdminPageBase
HtmlTransAdmin.aspxMicrosoft.SharePoint.ApplicationPages.HtmlTransAdminPageApplicationsManagementPage : GlobalAdminPageBase
DocTransAdmin.aspxMicrosoft.SharePoint.ApplicationPages.DocTransAdminPageApplicationsManagementPage : GlobalAdminPageBase
ManageFormTemplates.aspxMicrosoft.Office.InfoPath.Server. ApplicationPages.ManageFormTemplatesPage (Microsoft.Office.InfoPath.Server.Pages.dll)GridViewPageBase : AdminPageBase
ipfsConfig.aspxMicrosoft.Office.InfoPath.Server. ApplicationPages.FormServerConfigPage (Microsoft.Office.InfoPath.Server.dll)AdminPageBase
UploadFormTemplate.aspxMicrosoft.Office.InfoPath.Server. ApplicationPages.UploadFormTemplatePage (Microsoft.Office.InfoPath.Server.dll)AdminPageBase
ManageDataConnectionFiles.aspxMicrosoft.Office.InfoPath.Server. ApplicationPages.ManageDataConnectionFilesPage (Microsoft.Office.InfoPath.Server.Pages.dll)GridViewPageBase : AdminPageBase
ManageFormsServiceProxy.aspxMicrosoft.Office.InfoPath.Server. ApplicationPages.ManageFormsServiceProxyPage (Microsoft.Office.InfoPath.Server.Pages.dll)AdminPageBase
Shared Services Administration
managessp.aspxMicrosoft.Office.Server.Internal.UI.ManageSspPageCentralAdminPageBase

Building minimal SharePoint Central Administration Application Page.

Typical Central Admin Application Page inherits from Microsoft.SharePoint.ApplicationPages.GlobalAdminPageBase.
In order to be consistent with current pages we want to inherit the new:
• Operations Section page – from Microsoft.SharePoint.ApplicationPages.OperationsPage;
• Application Management page – from Microsoft.SharePoint.ApplicationPages.ApplicationsManagementPage;
Both OperationsPage and ApplicationsManagementPage classes overrides just one PageToRedirectOnCancel property from GlobalAdminPageBase.

Let’s build our first blank Central Admin Applications Management page:
Here is the code:
using System;
using System.Web;

namespace Sharepointalist.Samples.CentralAdmin
{
    public class ApplicationManagementSamplePage : Microsoft.SharePoint.ApplicationPages.ApplicationsManagementPage
    {

    }
}
Here is the web page:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="ApplicationManagementSamplePage.aspx.cs" Inherits="Sharepointalist.Samples.CentralAdmin.ApplicationManagementSamplePage, Sharepointalist.Samples.CentralAdmin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=5f18faed9b7b4caf" MasterPageFile="~/_admin/admin.master"%>

<asp:Content ID="Content1" contentplaceholderid="PlaceHolderAdditionalPageHead" runat="server">
</asp:Content>

<asp:Content ID="Content2" contentplaceholderid="PlaceHolderPageTitle" runat="server">
</asp:Content>

<asp:Content ID="Content3" contentplaceholderid="PlaceHolderPageTitleInTitleArea" runat="server">
</asp:Content>

<asp:content ID="Content4" contentplaceholderid="PlaceHolderPageDescription" runat="server">
</asp:content>

<asp:content ID="Content5" contentplaceholderid="PlaceHolderMain" runat="server">
</asp:content>

Deployment.

The best way to deploy Central Administration Application Pages is to create a feature. This is described numerous times, so I am not going to get deep this. Just don't forget:

In many cases we want to add a new link to our new page on the MOSS Central Administration Site. We can use Element Manifest file with CustomAction defined for that. Please refer to Custom Action Definitions and Default Custom Action Locations and IDs on MSDN for detailed info.
In short, we need to choose Location(Page) and select/create a Group for our link.
Possible Locations and Groups:
  • Operations Page - Microsoft.SharePoint.Administration.Operations.
    • Backup and Restore - BackupRestore;
    • Data Configuration - DataConfiguration;
    • Global Configuration - GlobalConfiguration;
    • Logging and Reporting - LoggingAndReporting;
    • Security Configuration - Security;
    • Topology and Services - Topology;
    • Upgrade and Migration - Upgrade;
    • Content Deployment - ContentDeployment;
  • Application Management Page - Microsoft.SharePoint.Administration.ApplicationManagement.
    • Application Security - ApplicationSecurity;
    • External Service Connections - ExternalService;
    • SharePoint Site Management - SiteManagement;
    • SharePoint Web Application Management - WebApplicationConfiguration;
    • Workflow Management - WorkflowManagement;
    • Search - SearchGroup;
    • InfoPath Forms Services - IPFSApplicationConfiguration;
    • Office SharePoint Server Shared Services - OfficeServerCoreServices;
  • Application Created Page - Microsoft.SharePoint.Administration.ApplicationCreated.
    • Links - Links;
  • Shared Services Administration Page - Office.Server.ServiceProvider.Administration.
    • User Profiles and My Sites - UAP;
    • Search - Search;
    • Excel Services Settings - ExcelServer;
    • Audiences - AUD;
    • Office SharePoint Usage Reporting - PortalAnalytics;
    • Business Data Catalog - BDC;

Here is a sample Elements.xml
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <CustomActionGroup
    Id="Sharepointalist.Samples.CentralAdmin.ApplicationManagementGroup"
    Location="Microsoft.SharePoint.Administration.ApplicationManagement"
    Title="Sharepointalist"
    Sequence="10" />
  <CustomAction 
    Id="Sharepointalist.Samples.CentralAdmin.ApplicationManagementSamplePage"
    GroupId="Sharepointalist.Samples.CentralAdmin.ApplicationManagementGroup"
    Title="Application Management Sample Page"
    Sequence="1"
    Location="Microsoft.SharePoint.Administration.ApplicationManagement">
    <UrlAction Url="/_admin/Sharepointalist/Samples/ApplicationManagementSamplePage.aspx"/>
  </CustomAction>
</Elements>

Here is a sample Feature.xml
<?xml version="1.0" encoding="utf-8" ?>
<Feature  Id="90AC28E1-F64B-42bb-AB51-C65590ED5CD4"
          Title="Sharepointalist Sample Central Administration Feature"
          Description="Sample Central Administration Feature. Please visit my web page at http://www.sharepointalist.com/"
          Version="1.0.0.0"
          Creator="http://www.sharepointalist.com/"
          ActivateOnDefault="True"
          Scope="Farm"
          xmlns="http://schemas.microsoft.com/sharepoint/"
          ReceiverAssembly="Sharepointalist.Samples.CentralAdmin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=5f18faed9b7b4caf"
          ReceiverClass="Sharepointalist.Samples.CentralAdmin.FeatureHandler">
  <Properties>
    <Property Key="GloballyAvailable" Value="true" />
  </Properties>
  <ElementManifests>
    <ElementManifest Location="Elements.xml"/>
  </ElementManifests>
</Feature>

Summary

This is enough to create a blank page. You can download an archive with the source code and deployment package here.