SharePoint: Get SPControlMode, which is associated with the current request
As I said before, I have custom display/edit/new forms for every usable list. Some of them are derived from a page base class. In some cases, e.g. basing on characteristics of a list item we are working at, I have to limit access to the forms (display/edit/new) for some users. These additional restrictions is a sort of superstructure over the SharePoint groups and permissions. I try to check conditions and deny access to the page as soon as possible in bounds of the page lifecycle. I prefer doing it in the base class inside OnInit-method, so it allows to avoid such actions as creation of controls, redirections and so on, that usually happen inside and between OnInit and OnLoad, and that are already vain if you deny access to the page, of course. In other words, it looks like the following:
public class MyBaseWebPartPage : WebPartPage { protected override void OnInit(EventArgs e) { if(!DoesUserHaveAccess()) SPUtility.HandleAccessDenied(new Exception("User doesn't have access!")); base.OnInit(e); } }
Very often to analyze page accessibility I need to know what mode (display/edit/new) corresponds to the current page, i.e. I need to know exactly whether it’s a display-page or an edit-page or a page to create a new item. SPContext.Current contains property FormContext, which, in turn, contains property FormMode. FormMode is a value of SPControlMode enumeration and indicates what mode is active now on page.
public enum SPControlMode { Invalid = 0, Display = 1, Edit = 2, New = 3, }
The only problem with FormMode is that, in the most cases, this property returns Invalid value inside OnInit-method. But, there is another way to find out the current mode of page. In schema.xml of any list there is a section <Forms>, which contains urls of aspx-pages that correspond to Display, Edit and New form modes.
<?xml version="1.0" encoding="utf-8"?> <List Name="SomeList" Title="Some list" Description="" Direction="0" BaseType="0" Url="Lists/SomeList" Type="100" Id="48C2DB5D-C74A-4246-ACB5-1FF536D37C19" xmlns="http://schemas.microsoft.com/sharepoint/" VersioningEnabled="TRUE" DisableAttachments="TRUE"> <MetaData> <Views>...</Views> <Fields>...</Fields> <ContentTypes>...</ContentTypes> <Forms> <Form Type="DisplayForm" Url="MyDispForm.aspx" WebPartZoneID="Main" /> <Form Type="EditForm" Url="MyEditForm.aspx" WebPartZoneID="Main" /> <Form Type="NewForm" Url="MyNewForm.aspx" WebPartZoneID="Main" /> </Forms> </MetaData> </List>
These aspx-pages are used for each item of the list, but they can be overridden by urls defined for content types.
If you have different content types, you, probably, have a section <FormUrls> inside content type definitions in schema.xml. As I said above, Urls defined in this section override the Urls defined in the section <Forms>, but only for this content type.
<?xml version="1.0" encoding="utf-8"?> <List Name="SomeList" Title="Some list" Description="" Direction="0" BaseType="0" Url="Lists/SomeList" Type="100" Id="48C2DB5D-C74A-4246-ACB5-1FF536D37C19" xmlns="http://schemas.microsoft.com/sharepoint/" VersioningEnabled="TRUE" DisableAttachments="TRUE"> <MetaData> <Views>...</Views> <Fields>...</Fields> <ContentTypes> <ContentType ID="0x0100204CA6A33177A5488DA2681769D46781" Name="SomeTypeOfItem" Group="List Content Types" Description="Create a new list item."> <FieldRefs>...</FieldRefs> <XmlDocuments> <XmlDocument NamespaceURI="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms/url"> <FormUrls xmlns="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms/url"> <Display>Lists/SomeList/MyView.aspx</Display> <Edit>Lists/SomeList/MyEdit.aspx</Edit> <New>Lists/SomeList/MyNew.aspx</New> </FormUrls> </XmlDocument> </XmlDocuments> <Folder>...</Folder> </ContentType> </ContentTypes> <Forms>...</Forms> </MetaData> </List>
So, by turns comparing urls, which is defined for a content type and/or a list, with url of the current Page.Request, we can definitely detect the current form mode of the page. The given approach can be implemented as the following method:
protected SPControlMode GetCurrentControlMode() { // if current control mode is already accessible and valid, return it if (SPContext.Current.FormContext != null && SPContext.Current.FormContext.FormMode != SPControlMode.Invalid) return SPContext.Current.FormContext.FormMode; // compare url of the current request with url of every page defined in list and/or in content type // get current content type SPContentType spContentType = GetCurrentContentType(); // store information about three possible form modes Dictionary<SPControlMode, KeyValuePair<string, PAGETYPE>> controlModeInfos = new Dictionary<SPControlMode, KeyValuePair<string, PAGETYPE>>(3); controlModeInfos[SPControlMode.Display] = new KeyValuePair<string, PAGETYPE>(spContentType != null ? spContentType.DisplayFormUrl : null, PAGETYPE.PAGE_DISPLAYFORM); controlModeInfos[SPControlMode.Edit] = new KeyValuePair<string, PAGETYPE>(spContentType != null ? spContentType.EditFormUrl : null, PAGETYPE.PAGE_EDITFORM); controlModeInfos[SPControlMode.New] = new KeyValuePair<string, PAGETYPE>(spContentType != null ? spContentType.NewFormUrl : null, PAGETYPE.PAGE_NEWFORM); // check each form mode whether it corresponds to the current request foreach (SPControlMode spControlMode in controlModeInfos.Keys) { bool res = false; // get a form url, that is defined in content type string cntTypeFormUrl = controlModeInfos[spControlMode].Key; // check whether the form url corresponds to the current request if (!string.IsNullOrEmpty(cntTypeFormUrl)) res = IsCurrentPage(cntTypeFormUrl); if (!res) { // get a form url, that is defined in list SPForm spForm = SPContext.Current.List.Forms[controlModeInfos[spControlMode].Value]; // check whether the form url corresponds to the current request if (spForm != null) res = IsCurrentPage(spForm.Url); } // return control mode if a coincidence is found if (res) return spControlMode; } return SPControlMode.Invalid; }
This method uses collection SPContext.Current.List.Forms to get access to urls defined in section <Forms> and properties SPContentType.DisplayFormUrl, SPContentType.EditFormUrl and SPContentType.NewFormUrl of the current content type to get access to urls defined in section <FormUrls>. The method GetCurrentContentType() works fine inside OnInit and was described in my previous post (SharePoint: Get content type, which is associated with the current request). The method IsCurrentPage is cited below:
protected bool IsCurrentPage(string pageName) { if (!string.IsNullOrEmpty(pageName)) { pageName = pageName.Trim('/'); int urlDelimeterIndex = pageName.LastIndexOf('/'); if (urlDelimeterIndex >= 0) pageName = pageName.Substring(urlDelimeterIndex + 1); return Page.Request.Url.AbsolutePath.EndsWith(pageName); } return false; }