Wednesday, June 27, 2012

Create Custom Web Part Page Template


Hello friends,

Most of us created new Web Part Page using Web Part Page Layouts provided by SharePoint 2010. SharePoint comes with the “Web Part Page” option to create pages from web part page layouts. SharePoint 2010 provides total of 8 Web Part Page Layouts. Following are the styles provided by SharePoint 2010 by default.


  1. Header, Footer, 3 Columns
  2. Full Page, Vertical
  3. Header, Left Column, Body
  4. Header, Right Column, Body
  5. Header, Footer, 2 Columns, 4 Rows
  6. Header, Footer, 4 Columns, Top Row
  7. Left Column, Header, Footer, Top Row, 3 Columns
  8. Right Column, Header, Footer, Top Row, 3 Columns

These all Web Part Templates are stored at location \Program Files\Common Files\Microsoft Shared\Web Server Extensions\60\TEMPLATE\1033\STS\DOCTEMP\SMARTPGS\.

You can have your own custom Web part Page Layouts created and stored in same directory. But as per my research and R&D Microsoft displays all these option when you click on Site Actions > View All Site Contents > Create > Web Part Page which calls spcf.aspx page. This page internally gives call to "/_vti_bin/owssvr.dll?CS=65001" to generate the page for each templates and this dll only support 8 Web Part Page Layout Templates only. So we need to develop our own spcf.aspx page which will generate the Page using our Custom Web Part Page Layout Template.

While doing so we will not touch the Web Part Page option provided by the SharePoint 2010 in Site Actions > View All Site Contents > Create

Let’s follow following steps to create our own custom Web Part Page option under Create action in Site Actions > View All Site Contents

Step1: Download the Customspcf.aspx page from here.

Step2: Once customspcf.aspx page is download/created copy into Mapped the directory [Layouts].

Step2

Step3: Create new Web Part Page Templates with the help of stspd1.aspx present under the \Program Files\Common Files\Microsoft Shared\Web Server Extensions\60\TEMPLATE\1033\STS\DOCTEMP\SMARTPGS\.

Create4-originalfiles

Step4: Make a copy of it and rename as per your naming convention (for e.g. CustomPage1.aspx). Modify the content of the page as per your Web Part Page Layout/Template. You can keep all these new templates in _Layouts/CustomWebPartTemplates Folder.

 Create5-Newfiles


Note: there is no need to keep your new templates in the same directory used by Microsoft SharePoint 2010.

Step5: Create new images for each templates you are adding, in our case five templates so we need five images. we can keep these images in the _Layouts/Images/MyWebPartLayoutImages directory.

Create6-NewImagesfiles

Step6: Modify content of customspfc.aspx as per your application such as the directory in which all Web Part Page layouts are kept, Naming convention followed for pages (step4), Images etc.


    1. Search for string “sourceFilePath” and replace the path with the path wherever you have kept for your custom page layouts
      (i.e. defined in Step4: _Layouts/CustomWebPartTemplates).
    2. Search for id “onetidWebPartPageTemplate” add number of options depending on your number of page Layouts (in our case five templates).
    3. Each option value must correspond to the page Layout Name (which is Name and followed by option value).


e.g. If option value is 1 then Page Layout should present in the page layout folder with “mywpptd1.apsx”.
If option value is 101 then Page Layout should present in the page layout folder with “mywpptd101.apsx”.

Create7-TemplatesNameDisplay

Step7: Create a new feature which will install new option “Custom Web Part Page” with similar functionality of “Web Part Page”. Make sure that this new option points to the new customspcf.aspx file when selected to create new Web Part Page using Template.

Create and empty element module and add following code into the element.xml file to change the highlighted part as per your settings.

<?xml version="1.0" encoding="utf-8"?>

<Elements xmlns="http://schemas.microsoft.com/sharepoint/">

<CustomAction

Id="CustomWebPartPageSettings"

Title="Custom - Web Part Page"

Description="Create a Web Part Page with Custom Web Part Page Template"

Location="Microsoft.SharePoint.Create"

GroupId="WebPages">

<UrlAction Url="_layouts/customspcf.aspx" />

</CustomAction>

</Elements>

Step8: Add new feature with scope to FARM. Add the newly created module from Step5 to this feature.

Step9: deploy feature to the Server.

After deployment, when you click on Site Actions > All Site Content.

Click on Create Link, If you have Silverlight installed you will get icon “Custom – Web Part Page”

Create1

else you will get link as “Custom – Web Part Page” under Pages and Sites

Create2

custom.aspx page

===============================================

  1. Create a new file customspcf.txt
  2. Copy the below text into it.
  3. then save and rename the customspcf.txt to customspcf.aspx.

<%@ Assembly Name="$SharePoint.Project.AssemblyFullName$" %>
<%@ Import Namespace="Microsoft.SharePoint.ApplicationPages" %>
<%@ 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" %>
<%@ Assembly Name="Microsoft.Web.CommandUI, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Page Language="C#" DynamicMasterPageFile="~masterurl/default.master" Inherits="Microsoft.SharePoint.WebControls.LayoutsPageBase"       %>


<script runat="server">
string L_GeneralError_Text = "An error has occurred.";
private void Page_Load(Object sender, EventArgs e)
{
    try
    {
        SPWeb spWeb = SPControl.GetContextWeb(Context);
        SPSite spServer = SPControl.GetContextSite(Context);
         // Make sure that the user is authenticated
        SPUtility.EnsureSessionCredentials(SPSessionCredentialsFlags.RequireAuthentication);
        // Create the select drop down control for the available Document Libraries only when the page is first loaded
        if (!Page.IsPostBack)
        {
            SPListCollection spLists = spWeb.Lists;           
            spLists.IncludeRootFolder = true;
            int iIndex = 0;
            bool bDocLibAvailable = false;
            for (int i = 0; i < spLists.Count; i++)
            {
                SPList spList = spLists[i];
                SPDocumentLibrary spDocLib = spList as SPDocumentLibrary;
                if ((!spList.Hidden) && (spList.BaseType == SPBaseType.DocumentLibrary) && spDocLib != null && !spDocLib.IsCatalog && (spList.BaseTemplate != SPListTemplateType.PictureLibrary))
                {
                    bool bHasPermission = false;
                    bool oldState = spServer.CatchAccessDeniedException;
                    try
                    {
                        spServer.CatchAccessDeniedException = false;
                        bHasPermission = spList.DoesUserHavePermissions(SPBasePermissions.AddListItems);
                    }
                    catch (UnauthorizedAccessException)
                    {
                    }
                    finally
                    {
                        spServer.CatchAccessDeniedException = oldState;
                    }
                    if (bHasPermission)
                    {
                        bDocLibAvailable = true;           
                        string value = SPEncode.HtmlEncode(spList.ID.ToString("B").ToUpper());
                        // ListItem encodes the text already, so no HTML encode here is needed
                        string text = spList.Title;
                        ListItem li = new ListItem(text, value);
                        if(iIndex == 0)
                        {
                            li.Selected = true;
                        }
                        onetidDocLibIDSelect.Items.Add(li);
                        iIndex++;
                    }
                }
            }
            // If no document library is available, disable the select drop down, and renders a link to create a document library
            if (iIndex == 0)
            {
                string L_NoneAvailable_Text = "None Available";
                onetidDocLibIDSelect.Disabled = true;
                ListItem li = new ListItem(L_NoneAvailable_Text);
                onetidDocLibIDSelect.Items.Add(li);
                string L_CreateDocLib1_Text = "Create a new ";
                string L_CreateDocLib2_Text = "Document Library";
                onetidCreateDocLibLabel.Text = L_CreateDocLib1_Text;
                onetidCreateDocLibLink.HRef = "new.aspx?ListTemplate=101&ListBaseType=1";
                onetidCreateDocLibLink.InnerText = L_CreateDocLib2_Text;
                btnCreate.Enabled = false;
            }
        }
        else // If the form posts back then we assume users press to enter button to create Web Part Pages
        {
            CreateWebPartPage();
        }
    }
    catch
    {
        Context.Server.Transfer("error.aspx?ErrorText=" + SPEncode.UrlEncode(L_GeneralError_Text));
        return;
    }
}

private void SubmitBtn_Click(Object sender, EventArgs e)
{
    try
    {
        CreateWebPartPage();
    }
    catch
    {
        Context.Server.Transfer("error.aspx?ErrorText=" + SPEncode.UrlEncode(L_GeneralError_Text));
        return;
    }
}
private void CreateWebPartPage()
{
    SPWeb spWeb = SPControl.GetContextWeb(Context);
    string templateName = Request.Form["WebPartPageTemplate"];
    // Validate the source file name
    if (templateName == null)
    {
        Context.Server.Transfer("error.aspx?ErrorText=" + SPEncode.UrlEncode(L_GeneralError_Text));
        return;
    }
    templateName = templateName.Trim();  // get rid of white spaces
    if (templateName.Length == 0)
    {
        Context.Server.Transfer("error.aspx?ErrorText=" + SPEncode.UrlEncode(L_GeneralError_Text));
        return;
    }
    templateName = templateName + ".aspx";
    if (templateName.Length > SPUtility.MaxLeafNameLength)
    {
        Context.Server.Transfer("error.aspx?ErrorText=" + SPEncode.UrlEncode(L_GeneralError_Text));
        return;
    }
    // Avoid characters like "..\..\" in the path
    if (templateName != System.IO.Path.GetFileName(templateName))
    {
        Context.Server.Transfer("error.aspx?ErrorText=" + SPEncode.UrlEncode(L_GeneralError_Text));
        return;
    }
    // Validate target file name
    string fileName = Request.Form["Title"];
    if (fileName == null)
    {
        Context.Server.Transfer("error.aspx?ErrorText=" + SPEncode.UrlEncode(L_GeneralError_Text));
        return;
    }
    fileName = fileName.Trim();  // get rid of white spaces
    if (fileName.Length == 0)
    {
        Context.Server.Transfer("error.aspx?ErrorText=" + SPEncode.UrlEncode(L_GeneralError_Text));
        return;
    }
    // Avoid characters like "..\..\" in the path
    if (fileName != System.IO.Path.GetFileName(fileName))
    {
        Context.Server.Transfer("error.aspx?ErrorText=" + SPEncode.UrlEncode(L_GeneralError_Text));
        return;
    }
    // Prepare the source file, assuming the Web Part Page templates live in
    // <Installation Path>\Template\Layouts\CustomWebPartTemplates
    string sourceFilePath = SPUtility.GetGenericSetupPath("Template\\") +
        "Layouts\\CustomWebPartTemplates\\";
   
    //string sourceFilePath = SPUtility.GetGenericSetupPath("Template\\") +
    //    spWeb.Language.ToString() + "\\" + spWeb.WebTemplate +
    //    "\\doctemp\\smartpgs\\";

    sourceFilePath = sourceFilePath + "mywpptd" + templateName;
    Response.Write(sourceFilePath);
    System.IO.StreamReader sr = new System.IO.StreamReader(sourceFilePath);
    //Response.Write("Ok");
    string content = sr.ReadToEnd();
    // Assuming the Web Part Page template has a Title Bar Web Part with the title place holder "_TitlePlaceHolder_"
    content = content.Replace("_TitlePlaceHolder_", fileName);
    // Save the target file into the database
    fileName += ".aspx";
   
    string doclibID = onetidDocLibIDSelect.Value;
    Guid guidDocLib = new Guid(doclibID);
    SPList doclib = spWeb.Lists[guidDocLib];
    string folderPath = doclib.RootFolder.Url;
    string targetFilePath = spWeb.Url + "/" + folderPath + "/" + fileName;
    // Convert the string into UTF8 encoded bytes
    System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
    System.Byte[] contentBytes = encoding.GetBytes(content);
    System.Byte[] bytes = new System.Byte[contentBytes.Length + 3];
    // Adding UTF8 byte order mark
    bytes[0] = 0xEF;
    bytes[1] = 0xBB;
    bytes[2] = 0xBF;
    contentBytes.CopyTo(bytes, 3);
    SPFileCollection fileCollection = spWeb.Files;
    if (OverwriteCheckBox.Checked)
    {
        SPFile spFile = spWeb.GetFile(targetFilePath);
        if (spFile != null && spFile.Exists)
        {
            SPFolder spFolder = spWeb.GetFolder(folderPath);
            spFolder.Files.Delete(targetFilePath);
        }
    }
    fileCollection.Add(targetFilePath, bytes);
    // Redirect to the newly created Web Part Page, with the toolpane opened in the Add Web Parts view
    Response.Redirect(targetFilePath + "?PageView=Shared&DisplayMode=Design&InitialTabId=Ribbon.WebPartPage&VisibilityContext=WSSWebPartPage");
}
</script>
<asp:Content ID="PageHead" ContentPlaceHolderID="PlaceHolderAdditionalPageHead" runat="server">
<% SPSite spServer = SPControl.GetContextSite(Context); SPWeb spWeb = SPControl.GetContextWeb(Context); %>
<head>
    <meta name="GENERATOR" content="Microsoft SharePoint"/>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <meta http-equiv="Expires" content="0"/>
   
    <title id="onetidTitle"><SharePoint:EncodedLiteral ID="EncodedLiteral1" runat="server" text="<%$Resources:wss,pagetitle_sharepoint%>" EncodeMethod='HtmlEncode'/></title>
<SharePoint:CssLink ID="CssLink1" runat="server"/>
    <SharePoint:Theme ID="Theme1" runat="server"/>
<SharePoint:ScriptLink ID="ScriptLink1" name="init.js" language="javascript" runat="server" />
<SharePoint:ScriptLink ID="ScriptLink2" name="core.js" language="javascript" runat="server" />
<SharePoint:CustomJSUrl ID="CustomJSUrl1" runat="server" />
<link type="text/xml" rel='alternate' href="_vti_bin/spdisco.aspx" />
</head>
<script type="text/javascript">
// <![CDATA[
var strImagePath = "../Images/MyWebPartLayoutImages/";
function DoValidateAndSubmit()
{
    var form = document.frmWebPage;
    form["Title"].value = TrimSpaces(form["Title"].value);
    if (form["Title"].value.length < 1)
    {
        var L_alert1_Text = "You must specify a non-blank value for Name.";
        window.alert(L_alert1_Text);
        form["Title"].focus();
        return false;
    }
    if (IndexOfIllegalCharInUrlLeafName(form["Title"].value) >= 0)
    {
        var L_IllegalChar_Text = "The file name contains invalid characters. Type another file name using valid characters.";
        window.alert(L_IllegalChar_Text);
        return false;
    }
    var index = document.frmWebPage.onetidDocLibIDSelect.selectedIndex;
    var ListValue = document.frmWebPage.onetidDocLibIDSelect.options[index].value;
    if (ListValue == "")
    {
    var L_NoDocumentLibary_Text = "No document library is selected for the save location.";
        alert(L_NoDocumentLibary_Text);
        return false;
    }
    return true;
}
function DoTemplateOptionChange()
{ULSEhF:;
    var frmWebPage = document.forms.<%SPHttpUtility.NoEncode(Form.ClientID,Response.Output);%>;
    var index = frmWebPage.WebPartPageTemplate.selectedIndex;
    frmWebPage.PreviewImage.src = strImagePath + "mywpptd" + frmWebPage.WebPartPageTemplate.options[index].value + ".png";
    frmWebPage.PreviewImage.alt = frmWebPage.WebPartPageTemplate.options[index].text;
}

// ]]>
</script>
</asp:Content>

<asp:Content ID="Main" ContentPlaceHolderID="PlaceHolderMain" runat="server">
  <TABLE class="ms-main" cellpadding="0" cellspacing="0" border="0" width="100%" height="100%">
    <!-- Banner -->
<%
string alternateHeader = SPControl.GetContextWeb(Context).AlternateHeader;
if (alternateHeader == null || alternateHeader == "")
{
%>
<TR>
  <TD COLSPAN=3 WIDTH=100%>
  <!--Top bar-->
 
  </TD>
</TR>
<%
}
else
{
    Server.Execute(alternateHeader);
}
%>
   
<TR>
<TD valign=top height=100% > </TD>
    <!-- Page overview -->
    <td><IMG SRC="/_layouts/images/blank.gif" width=10 height=1 alt=""></td>
    <td style="padding-top: 2px" valign="top" width="100%"> <table cellpadding=2 cellspacing=0><tr><td><IMG SRC="/_layouts/images/blank.gif" width=1 height=1 alt=""></td></tr></table>
      <TABLE  border="0" cellpadding="0" cellspacing="0" width="100%" id="diidPageOverview">
        <TR>
          <TD valign="top" colspan="3" style="padding-bottom: 10px">
            <TABLE cellpadding="0" border="0" id="Table1">
              <TR>
                <TD class="ms-descriptiontext" id="align01">
                    A Web Part Page is a collection of Web Parts that combines list data, timely information, or useful graphics into a dynamic Web page. The layout and content of a Web Part Page can be set for all users and optionally personalized by each user.  <a href="javascript:HelpWindowKey('WPPTour')">Take the Web Part Page tour!</a>
                </TD>
              </TR>
            </TABLE>
          </TD>
        </TR>
    <!-- New form UI -->
        <TR>
          <TD>
<FORM id="frmWebPage" onsubmit="return DoValidateAndSubmit();">
    <!-- Name -->
             <TABLE  border="0" width="100%" cellspacing="0" cellpadding="0" id="Table2">
                   <TR><TD class="ms-sectionline" height="1" colspan="4"><IMG SRC="/_layouts/images/blank.gif" width=1 height=1 alt=""></TD></TR>
                   <TR>
                     <TD nowrap rowspan="3"></TD>
                     <TD class="ms-descriptiontext" rowspan="3" valign="top"  id="align02">
                       <TABLE border="0" cellpadding="1" cellspacing="0" id="Table3">
                         <TR><TD class="ms-sectionheader" height="28" valign="top" id="200">Name</TD></TR>
                         <TR>
                           <TD id="onetidNameDescription" class="ms-descriptiontext">
                                 Type a file name for your Web Part Page.  The file name appears in headings and links throughout the site.
                           </TD>
                         </TR>
                       </TABLE>
                       <IMG SRC="/_layouts/images/blank.gif" width=275 height=1 alt="">
                     </TD>
                     <TD height="3" colspan="2" class="ms-authoringcontrols"><IMG SRC="/_layouts/images/blank.gif" width=1 height=1 alt=""></TD></TR>
                   </TR>
                   <TR>
                     <TD class="ms-authoringcontrols" width="10">&nbsp;</TD>
                     <TD class="ms-authoringcontrols" id="400">
                       Name:<BR>
                       <TABLE border="0" cellspacing="1">
                         <TR>
                           <TD>&nbsp;</TD>
                           <TD>
                             <INPUT id="onetidListTitle" type="Text" title="Name" name="Title" maxLength="123"><SPAN class="ms-authoringcontrols">.aspx</SPAN>
                           </TD>
                         </TR>
                         <TR>
                           <TD>&nbsp;</TD>
                           <TD class="ms-authoringcontrols">
                             <asp:CheckBox id="OverwriteCheckBox" title="Overwrite" runat="server"/>
                             Overwrite if file already exists?
                           </TD>
                         </TR>
                       </TABLE>
                     </TD>
                   </TR>
                   <TR><TD class="ms-authoringcontrols" colspan="2" height="6"><IMG SRC="/_layouts/images/blank.gif" width=1 height=1 alt=""></TD></TR>
                   <TR><TD colspan="2">&nbsp;</TD><TD class="ms-authoringcontrols" colspan="2" height="21">&nbsp;</TD></TR>
    <!-- Layout -->
                   <TR><TD class="ms-sectionline" height="1" colspan="4"><IMG SRC="/_layouts/images/blank.gif" width=1 height=1 alt=""></TD></TR>
                   <TR>
                     <TD nowrap rowspan="3"></TD>
                     <TD class="ms-descriptiontext" rowspan="3" valign="top"  id="align03">
                       <TABLE border="0" cellpadding="1" cellspacing="0" id="Table5">
                         <TR><TD class="ms-sectionheader" height="28" valign="top" id="500">Layout</TD></TR>
                         <TR>
                           <TD id="onetidLayoutDescription" class="ms-descriptiontext">
                                 Select a layout template to arrange Web Parts in zones on the page. Multiple Web Parts can be added to each zone. Specific zones allow Web Parts to be stacked in a horizontal or vertical direction, which is illustrated by differently colored Web Parts. If you do not add a Web Part to a zone, the zone collapses (unless it has a fixed width) and the other zones expand to fill unused space when you browse the Web Part Page.
                           </TD>
                         </TR>
                        <TR><TD class="ms-descriptiontext" height="20"><IMG SRC="/_layouts/images/blank.gif" width=1 height=1 alt=""></TD></TR>
                        <TR><TD align="center" class="ms-descriptiontext" height="6"><img src="/_layouts/MyApplication/Images/MyWebPartLayoutImages/mywpptd1.png" alt="Enterprise Layout – 33 / 66 Split" id="onetidPreviewImage" name="PreviewImage"/></TD></TR>
                        <TR><TD class="ms-descriptiontext" height="6"><IMG SRC="/_layouts/images/blank.gif" width=1 height=1 alt=""></TD></TR>
                       </TABLE>
                     </TD>
                     <TD height="3" colspan="2" class="ms-authoringcontrols"><IMG SRC="/_layouts/images/blank.gif" width=1 height=1 alt=""></TD></TR>
                   </TR>
                   <TR>
                     <TD class="ms-authoringcontrols" width="10">&nbsp;</TD>
                     <TD class="ms-authoringcontrols" id="700" valign="top">Choose a Layout Template:<FONT size="3">&nbsp;</FONT><BR>
                       <TABLE border="0" cellspacing="1" id="Table6">
                         <TR>
                           <TD>&nbsp;</TD>
                           <TD>
                             <!-- Assuming the templates are named mywpptdN.aspx and the image files are named as mywpptdN.gif, where N is from 9 to 12 -->
                             <!-- 0 to 8 are used by the default web part page layouts provided by SharePoint 2010. So we start from 9 -->
                             <SELECT id="onetidWebPartPageTemplate" name="WebPartPageTemplate" size="5" onchange="DoTemplateOptionChange()">
                               <OPTION value="1" selected="true">Enterprise Layout – 33 / 66 Split</OPTION>
                               <OPTION value="2">Enterprise Layout – 66 / 33 Split</OPTION>
                               <OPTION value="3">Enterprise Layout – 100% Span</OPTION>
                               <OPTION value="4">Enterprise Layout – 33 / 66 / 33 / 33 Split</OPTION>
                               <OPTION value="5">Enterprise Layout – 33 / 33 / 33 Split</OPTION>
                             </SELECT>
                           </TD>
                           <TD>&nbsp;</TD>
                         </TR>
                       </TABLE>
                     </TD>
                   </TR>
                   <TR><TD class="ms-authoringcontrols" colspan="2" height="6"><IMG SRC="/_layouts/images/blank.gif" width=1 height=1 alt=""></TD></TR>
                  <TR><TD colspan="2">&nbsp;</TD><TD class="ms-authoringcontrols" colspan="2" height="21">&nbsp;</TD></TR>
    <!-- Save Location -->
                   <TR><TD class="ms-sectionline" height="1" colspan="4"><IMG SRC="/_layouts/images/blank.gif" width=1 height=1 alt=""></TD></TR>
                   <TR>
                     <TD nowrap rowspan="3"></TD>
                     <TD class="ms-descriptiontext" rowspan="3" valign="top"  id="align04">
                       <TABLE border="0" cellpadding="1" cellspacing="0" id="Table7">
                         <TR><TD class="ms-sectionheader" height="28" valign="top" id="800">Save Location</TD></TR>
                         <TR>
                           <TD id="onetidSaveLocationDescription" class="ms-descriptiontext">
                                 Select the document library where you want the Web Part Page to be saved.
                           </TD>
                         </TR>
                       </TABLE>
                     </TD>
                     <TD height="3" colspan="2" class="ms-authoringcontrols"><IMG SRC="/_layouts/images/blank.gif" width=1 height=1 alt=""></TD></TR>
                   </TR>
                   <TR>
                     <TD class="ms-authoringcontrols" width="10">&nbsp;</TD>
                     <TD class="ms-authoringcontrols" id="900" valign="top"><label for="onetidDocLibIDSelect">Document Library</label>:<FONT size="3">&nbsp;</FONT><BR>
                       <TABLE border="0" cellspacing="1" id="Table8">
                         <TR>
                           <TD>&nbsp;</TD>
                           <TD>
                             <SELECT id="onetidDocLibIDSelect" runat="server"/>
                           </TD>
                           <TD>&nbsp;</TD>
                         </TR>
                         <TR>
                           <TD>&nbsp;</TD>
                           <TD class="ms-authoringcontrols">
                             <asp:Label id="onetidCreateDocLibLabel" runat="server"/><a id="onetidCreateDocLibLink"  runat="server"/>
                           </TD>
                           <TD>&nbsp;</TD>
                         </TR>
                       </TABLE>
                     </TD>
                   </TR>
                   <TR><TD class="ms-authoringcontrols" colspan="2" height="6"><IMG SRC="/_layouts/images/blank.gif" width=1 height=1 alt=""></TD></TR>
                   <TR><TD colspan="2">&nbsp;</TD><TD class="ms-authoringcontrols" colspan="2" height="21">&nbsp;</TD></TR>
  <!--OK/Cancel-->
               <TR><TD colspan="4" valign="top" height="25"><hr size="1"></TD></TR>
               <TR><TD colspan=4> <TABLE cellpadding=0 cellspacing=0 width=100%> <COLGROUP> <COL width=99%> <COL width=1%> </COLGROUP> <TR> <TD>&nbsp;</TD> <TD nowrap id=align06>
                  <asp:button ID="btnCreate" text="   Create   " AccessKey="C" CssClass="ms-ButtonHeightWidth" OnClick="SubmitBtn_Click" runat="server"/>
                  <INPUT id="onetidClose" class="ms-ButtonHeightWidth" type="button" onclick="window.parent.history.back()" value="   Cancel   ">
                  <SharePoint:FormDigest ID="FormDigest1" runat=server/>
               </TD> </TR> </TABLE> </TD></TR>
               <TR><TD colspan="4" height="60">&nbsp;</td></TR>
             </TABLE>
             <TD width="10px">&nbsp;</TD>
            </FORM>
          </TD>
        </TR>
      </TABLE>
    </TD>
    </TR>
  </TABLE>

</asp:Content>

<asp:Content ID="PageTitle" ContentPlaceHolderID="PlaceHolderPageTitle" runat="server">
Create Custom Web Part Pages
</asp:Content>

<asp:Content ID="PageTitleInTitleArea" ContentPlaceHolderID="PlaceHolderPageTitleInTitleArea" runat="server" >
Create Custom Web Part Pages
</asp:Content>

Tuesday, June 05, 2012

Global Error Handling in SharePoint 2010


Correct exception handling is an essential part of reliable and maintainable SharePoint applications. Most of the times in development stage of SharePoint 2010 we encounter the error “An unexpected error has occurred”. It always recommended code snipped always embedded in try catch block to log the errors. SharePoint also provides you the facility to map your custom page which can be displayed whenever there is any error. I have already explained this in my previous article of “UpdateMappedPage in SharePoint 2010” function.

There are several locations where an unhandled exception can occurred and there are different ways to capture the exception as explained below:

Page: In a SharePoint application, if an unhandled exception is not caught, it propagates to the page that was requested by the end user. SharePoint has a built-in global exception handler that will catch any unhandled exceptions and redirect the user to an appropriate error page (error mapped page). It is possible to handle unhandled exceptions in custom pages by responding to the Page_Error event provided by ASP.NET. The error page should not display any unhandled exception details to the end user because this can pose a security risk.

WebService: Within the Web service, you should catch all unhandled exceptions, log them and return a general exception message. This is also called exception shielding

WebPart: By default, if an unhandled exception occurs within a Web Part, the exception propagates to the Web page and triggers the unhandled exception handler of the page. This is not always the desired behavior. For example, it is possible in SharePoint to give end users the option of composing their own pages using Web Parts. When a Web Part throws an exception, it is difficult for the user to remove that Web Part from the page. To avoid this problem, you can implement an unhandled exception handler in this location

Purpose

It is not always possible to predict all exceptions that can occur with a SharePoint 2010 web site. Even sometimes developer do not include there code in proper try catch blocks causing the unhandled exception to occur. Therefore, we must implement handlers at system boundaries for unhandled exceptions. In general, exception handling for a SharePoint application is very similar to ASP.NET application. We can simply handle errors from the Application_Error function in the Global.aspx file; but in SharePoint, it never reaches that function; we can override this function by following way by creating our own http module.

Implementation

Step 1: Create an interface MyExceptionHandler using an IhttpModule interface.
An HTTP module is called on every request in response to the BeginRequest and EndRequest events. As a result, the module runs before and after a request is processed.

public class MyExceptionHandler : IHttpModule
{
}

Step 2: The Init function is called with the HttpApplication object. Attach an event handler to the HttpApplication.Error event.

/// <summary>
/// Attach an event handler to the HttpApplication.Error event
/// </summary>
/// <param name="context">Your Application</param>

public void Init(HttpApplication context)
{
    context.Error += new EventHandler(Application_Error);
}

Step 3: Implement Application_Error function to log error. This method gets the exception information, go down in depth and find the first error that raised the exception. Create the error message with the error info and the stack trace and the following code uses Microsoft Enterprise Library’s Logging Application Block to log the error. We can also configure whether we want to keep the log in a database, or in a flat file, or in other places, it’s totally depend on how you configure your Logging Application Block. You can also add code to redirect the user to custom error page or just implement Error Mapping page using UpdateMappedPage function of Web Application (previous article “UpdateMappedPage in SharePoint 2010”).

/// <summary>
/// Implement Application Error object
/// Use this method to log errors using logging functionality
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public void Application_Error(object sender, EventArgs e)
{
    HttpContext Context = HttpContext.Current;
    Exception exception;
    for (exception = Context.Server.GetLastError();
            exception.InnerException != null;
            exception = exception.InnerException) { }

    string LogDate = DateTime.Now.ToString("ddMMyyyy-HHmmfff");
    Logger.Write(String.Format("Exception Occured: {0} : {1} : {2}", new object[] {
         exception.Source, exception.Message, exception.StackTrace}),
         "General", 5, 1, System.Diagnostics.TraceEventType.Critical, LogDate);
}

Step 4: Register MyApplication.dll which contains the Module MyExceptionHandler in GAC.

Step 5: You need to put your IHttpModule before SharePoint specific modules in your web.config or otherwise your error routines may not work as you would expect.

<modules runAllManagedModulesForAllRequests="true">
<remove name="AnonymousIdentification" />
<remove name="FileAuthorization" />
<remove name="Profile" />
<remove name="WebDAVModule" />
<remove name="Session" />

<add name="MyExceptionHandler" preCondition="integratedMode" type="MyApplication.MyExceptionHandler, MyApplication, Version=1.0.0.0, Culture=neutral,PublicKeyToken=a0c7fe7135c06a56" />

<add name="SPRequestModule" preCondition="integratedMode" type="Microsoft.SharePoint.ApplicationRuntime.SPRequestModule, Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />

<add name="ScriptModule" preCondition="integratedMode" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />

<add name="SharePoint14Module" preCondition="integratedMode" />

<add name="StateServiceModule" type="Microsoft.Office.Server.Administration.StateModule, Microsoft.Office.Server, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />

<add name="PublishingHttpModule" type="Microsoft.SharePoint.Publishing.PublishingHttpModule, Microsoft.SharePoint.Publishing, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />

</modules>

References: http://msdn.microsoft.com/en-us/library/ff647598.aspx