Saturday, December 20, 2008

SharePoint 2007 (MOSS/WSS) - how to remove "Download a Copy" context menu from a Document Library



Go to your 12 hive\TEMPLATE\LAYOUTS\1033 folder. Open up the Core.js file. Find the function AddSendSubMenu. Go to the last 3 lines:

strAction = "STSNavigate('" + ctx.HttpRoot + "/_layouts/download.aspx?" + "SourceUrl=" + currentItemEscapedFileUrl + "&Source=" + GetSource() + "&FldUrl=" + escapeProperly(ctx.SendToLocationUrl) + "')"; ;
menuOption = CAMOpt(sm, L_DownloadACopy_Text, strAction, "");
menuOption.id = "ID_DownloadACopy";

Now if you want to remove "Download a Copy" option from all the document libraries then comment all three lines.
If you want to remove it for some custom List Definition that you have created you may do like:
if(ctx.listTemplate !=10001)
{

strAction = "STSNavigate('" + ctx.HttpRoot + "/_layouts/download.aspx?" + "SourceUrl=" + currentItemEscapedFileUrl + "&Source=" + GetSource() + "&FldUrl=" + escapeProperly(ctx.SendToLocationUrl) + "')"; ;
menuOption = CAMOpt(sm, L_DownloadACopy_Text, strAction, "");
menuOption.id = "ID_DownloadACopy";
}

Where 10001 was your custom list template id.

If you want to do it for a specific Document Library then you would do like this:

if(ctx.listName !="{28958B49-8C76-4987-815C-CF5A107FF522}")
{

strAction = "STSNavigate('" + ctx.HttpRoot + "/_layouts/download.aspx?" + "SourceUrl=" + currentItemEscapedFileUrl + "&Source=" + GetSource() + "&FldUrl=" + escapeProperly(ctx.SendToLocationUrl) + "')"; ;
menuOption = CAMOpt(sm, L_DownloadACopy_Text, strAction, "");
menuOption.id = "ID_DownloadACopy";
}

As you can see you have to pass the list GUID as listName.


Actual post:
http://blogs.msdn.com/pranab/archive/2008/12/06/sharepoint-2007-moss-wss-how-to-remove-download-a-copy-context-menu-from-a-document-library.aspx

SharePoint 2007 (MOSS/WSS) - Adding header and footer in Word Document (.docx) with ItemAdded Event Receiver using OpenXML

I used OpenXML to add the two metadata column values - document name as the header and modified date as footer while someone upload a document in document library. Please include a reference of  WindowsBase and DocumentFormat.OpenXml in the project. WindowsBase is included in .Net framework 3.0/3.5 and you have to download DocumentFormat.OpenXml separately.
Here is the code:
using System;
using System.Security.Permissions;
using System.Runtime.InteropServices;
using Microsoft.SharePoint;
using System.IO;
using System.IO.Packaging;
using DocumentFormat.OpenXml.Packaging;
using System.Xml;
using System.Collections.Generic;

namespace AddHeaderFooterReceiver
{
public class AddHeaderFooterEventReceiver : SPItemEventReceiver
{
public string GetFooter()
{
string footerVal = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?><w:ftr xmlns:ve=\"http://schemas.openxmlformats.org/markup-compatibility/2006\" xmlns:o=\"urn:schemas-microsoft-com:office:office\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\" xmlns:m=\"http://schemas.openxmlformats.org/officeDocument/2006/math\" xmlns:v=\"urn:schemas-microsoft-com:vml\" xmlns:wp=\"http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing\" xmlns:w10=\"urn:schemas-microsoft-com:office:word\" xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\" xmlns:wne=\"http://schemas.microsoft.com/office/word/2006/wordml\"><w:p w:rsidR=\"00C24C70\" w:rsidRDefault=\"00C24C70\"><w:pPr><w:pStyle w:val=\"Footer\" /></w:pPr><w:r><w:t>Hi</w:t></w:r></w:p><w:p w:rsidR=\"00C24C70\" w:rsidRDefault=\"00C24C70\"><w:pPr><w:pStyle w:val=\"Footer\" /></w:pPr></w:p></w:ftr>";
return footerVal;
}
public string GetHeader()
{
string headerVal = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?><w:hdr xmlns:ve=\"http://schemas.openxmlformats.org/markup-compatibility/2006\" xmlns:o=\"urn:schemas-microsoft-com:office:office\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\" xmlns:m=\"http://schemas.openxmlformats.org/officeDocument/2006/math\" xmlns:v=\"urn:schemas-microsoft-com:vml\" xmlns:wp=\"http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing\" xmlns:w10=\"urn:schemas-microsoft-com:office:word\" xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\" xmlns:wne=\"http://schemas.microsoft.com/office/word/2006/wordml\"><w:p w:rsidR=\"00C8737A\" w:rsidRDefault=\"00C8737A\"><w:pPr><w:pStyle w:val=\"Header\" /></w:pPr><w:r><w:t>hello</w:t></w:r></w:p><w:p w:rsidR=\"00C8737A\" w:rsidRDefault=\"00C8737A\"><w:pPr><w:pStyle w:val=\"Header\" /> </w:pPr></w:p></w:hdr>";
return headerVal;
}
public void WDAddHeader(Stream headerContent, Stream fileContent)
{
// Given a document name, and a stream containing valid header content,
// add the stream content as a header in the document.

const string documentRelationshipType = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument";
const string wordmlNamespace = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
const string headerContentType = "application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml";
const string headerRelationshipType = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/header";
const string relationshipNamespace = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";

PackagePart documentPart = null;

using (Package wdPackage = Package.Open(fileContent, FileMode.Open, FileAccess.ReadWrite))
{
// Get the main document part (document.xml).
foreach (System.IO.Packaging.PackageRelationship relationship in wdPackage.GetRelationshipsByType(documentRelationshipType))
{
Uri documentUri = PackUriHelper.ResolvePartUri(new Uri("/", UriKind.Relative), relationship.TargetUri);
documentPart = wdPackage.GetPart(documentUri);
// There is only one officeDocument.
break;
}

Uri uriHeader = new Uri("/word/header1.xml", UriKind.Relative);
if (wdPackage.PartExists(uriHeader))
{
// Although you can delete the relationship
// to the existing node, the next time you save
// the document after making changes, Word
// will delete the relationship.
wdPackage.DeletePart(uriHeader);
}
// Create the header part.
PackagePart headerPart = wdPackage.CreatePart(uriHeader, headerContentType);

// Load the content from the input stream.
// This may seem redundant, but you must read it at some point.
// If you ever need to analyze the contents of the header,
// at least it is already in an XmlDocument.
// This code uses the XmlDocument object only as
// a "pass-through" -- giving it a place to hold as
// it moves from the input stream to the output stream.
// The code could read each byte from the input stream, and
// write each byte to the output stream, but this seems
// simpler...
XmlDocument headerDoc = new XmlDocument();
headerContent.Position = 0;
headerDoc.Load(headerContent);

// Write the header out to its part.
headerDoc.Save(headerPart.GetStream());

// Create the document's relationship to the new part.
PackageRelationship rel = documentPart.CreateRelationship(uriHeader, TargetMode.Internal, headerRelationshipType);
string relID = rel.Id;

// Manage namespaces to perform Xml XPath queries.
NameTable nt = new NameTable();
XmlNamespaceManager nsManager = new XmlNamespaceManager(nt);
nsManager.AddNamespace("w", wordmlNamespace);

// Get the document part from the package.
// Load the XML in the part into an XmlDocument instance.
XmlDocument xdoc = new XmlDocument(nt);
xdoc.Load(documentPart.GetStream());

// Find the node containing the document layout.
XmlNode targetNode = xdoc.SelectSingleNode("//w:sectPr", nsManager);
if (targetNode != null)
{
// Delete any existing references to headers.
XmlNodeList headerNodes = targetNode.SelectNodes("./w:headerReference", nsManager);
foreach (System.Xml.XmlNode headerNode in headerNodes)
{
targetNode.RemoveChild(headerNode);
}

// Create the new header reference node.
XmlElement node = xdoc.CreateElement("w:headerReference", wordmlNamespace);
XmlAttribute attr = node.Attributes.Append(xdoc.CreateAttribute("r:id", relationshipNamespace));
attr.Value = relID;
node.Attributes.Append(attr);
targetNode.InsertBefore(node, targetNode.FirstChild);
}

// Save the document XML back to its part.
xdoc.Save(documentPart.GetStream(FileMode.Create, FileAccess.Write));
}
}

public void WDAddFooter(Stream footerContent, Stream fileContent)
{
// Given a document name, and a stream containing valid footer content,
// add the stream content as a footer in the document.

const string documentRelationshipType = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument";
const string wordmlNamespace = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
const string footerContentType = "application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml";
const string footerRelationshipType = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer";
const string relationshipNamespace = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";

PackagePart documentPart = null;

using (Package wdPackage = Package.Open(fileContent, FileMode.Open, FileAccess.ReadWrite))
{
// Get the main document part (document.xml).
foreach (System.IO.Packaging.PackageRelationship relationship in wdPackage.GetRelationshipsByType(documentRelationshipType))
{
Uri documentUri = PackUriHelper.ResolvePartUri(new Uri("/", UriKind.Relative), relationship.TargetUri);
documentPart = wdPackage.GetPart(documentUri);
// There is only one officeDocument.
break;
}

Uri uriFooter = new Uri("/word/footer1.xml", UriKind.Relative);
if (wdPackage.PartExists(uriFooter))
{
// Although you can delete the relationship
// to the existing node, the next time you save
// the document after making changes, Word
// will delete the relationship.
wdPackage.DeletePart(uriFooter);
}
// Create the footer part.
PackagePart footerPart = wdPackage.CreatePart(uriFooter, footerContentType);

// Load the content from the input stream.
// This may seem redundant, but you must read it at some point.
// If you ever need to analyze the contents of the footer,
// at least it is already in an XmlDocument.
// This code uses the XmlDocument object only as
// a "pass-through" -- giving it a place to hold as
// it moves from the input stream to the output stream.
// The code could read each byte from the input stream, and
// write each byte to the output stream, but this seems
// simpler...
XmlDocument footerDoc = new XmlDocument();
footerContent.Position = 0;
footerDoc.Load(footerContent);

// Write the footer out to its part.
footerDoc.Save(footerPart.GetStream());

// Create the document's relationship to the new part.
PackageRelationship rel = documentPart.CreateRelationship(uriFooter, TargetMode.Internal, footerRelationshipType);
string relID = rel.Id;

// Manage namespaces to perform Xml XPath queries.
NameTable nt = new NameTable();
XmlNamespaceManager nsManager = new XmlNamespaceManager(nt);
nsManager.AddNamespace("w", wordmlNamespace);

// Get the document part from the package.
// Load the XML in the part into an XmlDocument instance.
XmlDocument xdoc = new XmlDocument(nt);
xdoc.Load(documentPart.GetStream());

// Find the node containing the document layout.
XmlNode targetNode = xdoc.SelectSingleNode("//w:sectPr", nsManager);
if (targetNode != null)
{
// Delete any existing references to footers.
XmlNodeList footerNodes = targetNode.SelectNodes("./w:footerReference", nsManager);
foreach (System.Xml.XmlNode footerNode in footerNodes)
{
targetNode.RemoveChild(footerNode);
}

// Create the new footer reference node.
XmlElement node = xdoc.CreateElement("w:footerReference", wordmlNamespace);
XmlAttribute attr = node.Attributes.Append(xdoc.CreateAttribute("r:id", relationshipNamespace));
attr.Value = relID;
node.Attributes.Append(attr);
targetNode.InsertBefore(node, targetNode.FirstChild);
}

// Save the document XML back to its part.
xdoc.Save(documentPart.GetStream(FileMode.Create, FileAccess.Write));
}
}

public override void ItemAdded(SPItemEventProperties properties)
{
string extension = properties.ListItem.Url.Substring(properties.ListItem.Url.LastIndexOf(".") + 1);
if (extension == "docx")
{
string headerContent = GetHeader().Replace("hello", properties.ListItem["Name"].ToString());
string footerContent = GetFooter().Replace("Hi", properties.ListItem["Modified"].ToString());
Stream headerStream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(headerContent));
Stream footerStream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(footerContent));
MemoryStream fileStream = new MemoryStream();
fileStream.Write(properties.ListItem.File.OpenBinary(), 0, (int)properties.ListItem.File.TotalLength);
WDAddHeader(headerStream, fileStream);
WDAddFooter(footerStream, fileStream);
properties.ListItem.File.SaveBinary(fileStream);
}
}
}
}


Actual post: http://blogs.msdn.com/pranab/archive/2008/12/18/sharepoint-2007-moss-wss-adding-header-and-footer-in-word-document-docx-with-itemadded-event-receiver-using-openxml.aspx

Sunday, October 5, 2008

The server could not complete your request. Contact your internet service provider or Web server administrator to make sure that the server has the Fr

Problem:

While trying to open a site in the sharepoint designer, you get the error
The server could not complete your request. Contact your internet service provider or Web server administrator to make sure that the server has the Frontpage Server Extensions or SharePoint Services installed

Fix:

  1. Go to the application server
    IIS -> Application pools -> select the corresponding application pool -> right click -> recycle the application pool.
  2. If you are still unable to get the page opened, try to open an individual .aspx page located directly under the site folder. Once the page is opened properly, try to open the desired actual '.aspx' or the '.master' file.

Thursday, September 4, 2008

An error occurred during the processing of the page. The server block is not well formed.

Reason:

Custom page layout/aspx page has some tags that were registered in the custom master page. So, when the custom page layout looking for 'registered tags' in the default master page.. failing to bind.
Precisely, Actual custom masterpage is not binded to the custom page layout due to the late binding.

Solution:
Right click on the actual master page in the SPD and select 'set as custom master page'.

Sunday, August 3, 2008

Tabbed Pages with multiple zones

Peter Allen explained about the tabs on the page here.
I am gonna extend this part to include multiple webpart zones on the page.
Step1: Coding the Tabbed page.
Open a notepad and paste the below code. Save the file as 'TabbedPage.aspx'.

<%@ Page Language="C#" MasterPageFile="~masterurl/default.master" inherits="Microsoft.SharePoint.WebPartPages.WebPartPage, Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" meta:progid="SharePoint.WebPartPage.Document" %>
<%@ Register tagprefix="WebPartPages" namespace="Microsoft.SharePoint.WebPartPages" assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

<asp:Content runat="server" ContentPlaceHolderID="PlaceHolderAdditionalPageHead">

<script type="text/javascript">
if(typeof jQuery=="undefined")
{
var jQPath="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/";
document.write("<script src='",jQPath,"jquery.min.js' type='text/javascript'><\/script>");}
</script>

<style>#tabs ul.tabNavigation{ margin: 0; padding: 0; list-style: none; height: 20px; /* Push the tabs 1px down to hide the top-border of the tabbedWindow */ position: relative; top: 1px; border-bottom: #998b7d 1px solid;}#tabs ul.tabNavigation li{ float: left; padding: 0; margin: 0 5px 0 0; background: none;}#tabs ul.tabNavigation a{ background-color: #fff; border: 1px solid #bbb; display: block; padding: 4px 0 1px; text-decoration:none}#tabs ul.tabNavigation a.selected{ font-weight: bolder; background-color: #C0C0C0; border-bottom: #bbb 1px solid;}#tabs ul.tabNavigation a span{ padding: 0 10px;}#tabs div.tabbedWindow{
background-color: #fff;
}#tabs ul.tabNavigation a:hover{ background-color: #F0F0F0 ;}
</style><script type="text/javascript">

$(function () { var tabContainers = $('div#tabs > .tabbedWindow'); tabContainers.hide().filter('#tab-1').show(); $('div#tabs ul.tabNavigation a').click(function () { tabContainers.hide(); tabContainers.filter(this.hash).show(); $('div#tabs ul.tabNavigation a').removeClass('ms-topnavselected selected'); $(this).addClass('ms-topnavselected selected'); return false; }).filter('#tab-1').click(); }); </script>
</asp:Content>

<asp:Content runat="server" ContentPlaceHolderID="PlaceHolderMain">

<table cellpadding="4" cellspacing="0" border="0" width="100%">
<tr>
<td id="_invisibleIfEmpty" name="_invisibleIfEmpty" colspan="3" valign="top" width="100%">
<WebPartPages:WebPartZone runat="server" Title="loc:Header" ID="Header" FrameType="TitleBarOnly">
<ZoneTemplate>
</ZoneTemplate></WebPartPages:WebPartZone> </td> </tr>



<tr> <td id="_invisibleIfEmpty" name="_invisibleIfEmpty" colspan="3" valign="top" width="100%"> <WebPartPages:WebPartZone runat="server" Title="loc:Tab" ID="Tab"><ZoneTemplate></ZoneTemplate></WebPartPages:WebPartZone> </td> </tr> <tr> <td id="_invisibleIfEmpty" name="_invisibleIfEmpty" valign="top" height="100%">
<div id="tabs"> <div class="tabbedWindow" id="tab-1"><WebPartPages:WebPartZone id="ID1" runat="server" title="Zone Tab 1"><ZoneTemplate></ZoneTemplate></WebPartPages:WebPartZone> </div>
<div class="tabbedWindow" id="tab-2"><WebPartPages:WebPartZone id="ID2" runat="server" title="Zone Tab 2"><ZoneTemplate></ZoneTemplate></WebPartPages:WebPartZone> </div> <div class="tabbedWindow" id="tab-3"><WebPartPages:WebPartZone id="ID3" runat="server" title="Zone Tab 3"><ZoneTemplate></ZoneTemplate></WebPartPages:WebPartZone> </div>
<div class="tabbedWindow" id="tab-4"><WebPartPages:WebPartZone id="ID4" runat="server" title="Zone Tab 4"><ZoneTemplate></ZoneTemplate></WebPartPages:WebPartZone> </div>
<div class="tabbedWindow" id="tab-5"><WebPartPages:WebPartZone id="ID5" runat="server" title="Zone Tab 5"><ZoneTemplate></ZoneTemplate></WebPartPages:WebPartZone> </div>

<div class="tabbedWindow" id="tab-6"><WebPartPages:WebPartZone id="ID6" runat="server" title="Zone Tab 6"><ZoneTemplate></ZoneTemplate></WebPartPages:WebPartZone> </div> <div class="tabbedWindow" id="tab-7"><WebPartPages:WebPartZone id="ID7" runat="server" title="Zone Tab 7"><ZoneTemplate></ZoneTemplate></WebPartPages:WebPartZone> </div>
<div class="tabbedWindow" id="tab-8"><WebPartPages:WebPartZone id="ID8" runat="server" title="Zone Tab 8"><ZoneTemplate></ZoneTemplate></WebPartPages:WebPartZone> </div>
<div class="tabbedWindow" id="tab-9"><WebPartPages:WebPartZone id="ID9" runat="server" title="Zone Tab 9"><ZoneTemplate></ZoneTemplate></WebPartPages:WebPartZone> </div>
<div class="waste"></div> </div>
</td>



<td id="_invisibleIfEmpty" name="_invisibleIfEmpty" valign="top" height="100%">
<div id="tabs"> <div class="tabbedWindow" id="tab-1"><WebPartPages:WebPartZone id="ID10" runat="server" title="Zone Tab 10"><ZoneTemplate></ZoneTemplate></WebPartPages:WebPartZone> </div>
<div class="tabbedWindow" id="tab-2"><WebPartPages:WebPartZone id="ID11" runat="server" title="Zone Tab 11"><ZoneTemplate></ZoneTemplate></WebPartPages:WebPartZone> </div>
<div class="tabbedWindow" id="tab-3"><WebPartPages:WebPartZone id="ID12" runat="server" title="Zone Tab 12"><ZoneTemplate></ZoneTemplate></WebPartPages:WebPartZone> </div>
<div class="tabbedWindow" id="tab-4"><WebPartPages:WebPartZone id="ID13" runat="server" title="Zone Tab 13"><ZoneTemplate></ZoneTemplate></WebPartPages:WebPartZone> </div>
<div class="tabbedWindow" id="tab-5"><WebPartPages:WebPartZone id="ID14" runat="server" title="Zone Tab 14"><ZoneTemplate></ZoneTemplate></WebPartPages:WebPartZone> </div>
<div class="tabbedWindow" id="tab-6"><WebPartPages:WebPartZone id="ID15" runat="server" title="Zone Tab 15"><ZoneTemplate></ZoneTemplate></WebPartPages:WebPartZone> </div>
<div class="tabbedWindow" id="tab-7"><WebPartPages:WebPartZone id="ID16" runat="server" title="Zone Tab 16"><ZoneTemplate></ZoneTemplate></WebPartPages:WebPartZone> </div>
<div class="tabbedWindow" id="tab-8"><WebPartPages:WebPartZone id="ID17" runat="server" title="Zone Tab 17"><ZoneTemplate></ZoneTemplate></WebPartPages:WebPartZone> </div>
<div class="tabbedWindow" id="tab-9"><WebPartPages:WebPartZone id="ID18" runat="server" title="Zone Tab 18"><ZoneTemplate></ZoneTemplate></WebPartPages:WebPartZone> </div> </div></td>



<td id="_invisibleIfEmpty" name="_invisibleIfEmpty" valign="top" height="100%">
<div id="tabs"> <div class="tabbedWindow" id="tab-1"><WebPartPages:WebPartZone id="ID19" runat="server" title="Zone Tab 19"><ZoneTemplate></ZoneTemplate></WebPartPages:WebPartZone> </div>
<div class="tabbedWindow" id="tab-2"><WebPartPages:WebPartZone id="ID20" runat="server" title="Zone Tab 20"><ZoneTemplate></ZoneTemplate></WebPartPages:WebPartZone> </div>
<div class="tabbedWindow" id="tab-3"><WebPartPages:WebPartZone id="ID21" runat="server" title="Zone Tab 21"><ZoneTemplate></ZoneTemplate></WebPartPages:WebPartZone> </div><div class="tabbedWindow" id="tab-4"><WebPartPages:WebPartZone id="ID22" runat="server" title="Zone Tab 22"><ZoneTemplate></ZoneTemplate></WebPartPages:WebPartZone> </div>
<div class="tabbedWindow" id="tab-5"><WebPartPages:WebPartZone id="ID23" runat="server" title="Zone Tab 23"><ZoneTemplate></ZoneTemplate></WebPartPages:WebPartZone> </div>
<div class="tabbedWindow" id="tab-6"><WebPartPages:WebPartZone id="ID24" runat="server" title="Zone Tab 24"><ZoneTemplate></ZoneTemplate></WebPartPages:WebPartZone> </div>
<div class="tabbedWindow" id="tab-7"><WebPartPages:WebPartZone id="ID25" runat="server" title="Zone Tab 25"><ZoneTemplate></ZoneTemplate></WebPartPages:WebPartZone> </div>
<div class="tabbedWindow" id="tab-8"><WebPartPages:WebPartZone id="ID26" runat="server" title="Zone Tab 26"><ZoneTemplate></ZoneTemplate></WebPartPages:WebPartZone> </div>
<div class="tabbedWindow" id="tab-9"><WebPartPages:WebPartZone id="ID27" runat="server" title="Zone Tab 27"><ZoneTemplate></ZoneTemplate></WebPartPages:WebPartZone> </div>
</div></td>

</tr> <tr> <td id="_invisibleIfEmpty" name="_invisibleIfEmpty" colspan="3" valign="top" width="100%"> <WebPartPages:WebPartZone runat="server" Title="loc:Footer" ID="Footer" FrameType="TitleBarOnly"><ZoneTemplate></ZoneTemplate></WebPartPages:WebPartZone> </td> </tr> <tr>
</tr> <script language="javascript">if(typeof(MSOLayout_MakeInvisibleIfEmpty) == "function") {MSOLayout_MakeInvisibleIfEmpty();}</script></table></asp:Content>
<asp:Content runat="server" ContentPlaceHolderID="PlaceHolderPageTitle"> Site</asp:Content>


I embedded the parallel zones with the extra DIVs and seperated by HTML TD(Table Data) node. make sure that you follow the below standrds:

  1. Every extra TD should have the name defined with a specific name.
    <td id="_invisibleIfEmpty" name="_invisibleIfEmpty" valign="top" height="100%"> 
  2. Every TD must have a DIV defined with a standard name "tabs", thats where the code gets the reference.
    <div id="tabs">
Step2:Upload the aspx page to a doc lib.
Go to any document library and upload the dashboard.aspx page. After uploading the page, moify the page (site actions -> Edit Page).
Step3: Linking the tabs with the actual webpart zones.

Click on the 'tabs' zone's add webpart link and add a content editor webpart. Modify the CEWP Source Editor and paste the below code.

<!-- Code to hide Tab Page Help Link -->
<script type="text/javascript">
$(document).ready(function() {
$('#TabPageHelp').hide(); });
</script>
<!-- Code to add Tabs -->
<div id="tabs">
<ul class="tabNavigation ms-WPBody">
<li><a href="#tab-1" class="selected ms-topnavselected"><span>Tab-1</span></a></li>
<li><a href="#tab-2" ><span>Tab-2</span></a></li>
<li><a href="#tab-3" ><span>Tab-3</span></a></li>
<li><a href="#tab-4" ><span>Tab-4</span></a></li>
<li><a href="#tab-5" ><span>Tab-5</span></a></li>
<li><a href="#tab-6" ><span>Tab-6</span></a></li>
<li><a href="#tab-7" ><span>Tab-7</span></a></li>
<li><a href="#tab-8" ><span>Tab-8</span></a></li>
<li><a href="#tab-9" ><span>Tab-9</span></a></li> </ul>
<div style="clear: both"></div></div>
Step4: adding webparts.
Now, when you click on the 'Tab1', you see the three zones with three parallel Table Data structure. By selecting the desired tab, add web parts to the zones.

Thursday, July 24, 2008

Login popup prompted to enter the credentials again and again when accessing FQDN through Windows Vista

Scenario:
Login popup is prompted recursively to enter the id pwd credentials again and again while opening a document located in the sharepoint area.

Reason:
This bug is nothing to do any thing with the 'Sharepoint'.
You will get prompted while accessing any office document.
By default, On a Windows Vista-based computer, you do not configure a proxy in Windows Internet Explorer and you use Web Distributed Authoring and Versioning (WebDav) to access a fully qualified domain names (FQDN) site.

In Windows Vista, Internet Explorer uses the Web Client service when you use Internet Explorer to access a WebDAV resource. The Web Client Service uses Windows HTTP Services (WinHTTP) to perform the network I/O to the remote host. WinHTTP sends user credentials only in response to requests that occur on a local intranet site.

WinHTTP does not check the security zone settings in Internet Explorer to determine whether a Web site is in a zone that lets credentials be sent automatically.If no proxy is configured, WinHTTP sends credentials only to local intranet sites.Note If the URL contains no period in the server’s name.

eg. the server is assumed to be on a local intranet site:
http://sharepoint/davshare.

If the URL contains periods, the server is assumed to be on the Internet. The periods indicate that you use an FQDN address. Therefore, no credentials are automatically sent to this server unless a proxy is configured and unless this server is indicated for proxy bypass.Note A server can be indicated for proxy bypass either through the bypass list or through the proxy configuration script.In this case, you are prompted to enter your credentials when the Web site asks for credentials. Even in this case, the security zone settings are ignored.

Fix:
  • Install Windows Vista Service Pack 1 or a later service pack.
  • Start -> Run -> regedit
  • Traverse to
    HKEY_LOCAL_MACHINE > SYSTEM > CurrentControlSet > Services > WebClient > Parameters
  • Right-click the 'Parameters' subkey, and choose New > Multi-String Value.
  • Type the name AuthForwardServerList.
  • Open the AuthForwardServerList value and type in the list of SharePoint server URL's that are trusted for your organization - one URL per line.
  • Start > Admin Tools> SERVICES -> Restart the WebClient service. Or reboot the PC.

Wednesday, June 11, 2008

Modifying the 'My Links' URL with the Sharepoint Deligate control

Allright, fresh day and refreshing requirement.. a request from the client that they do not need a 'my site' previlege available to all the users in the company. But they remain would like to use the 'My Links' link after the welcome control on each page. They also wanted the 'My Profile' option remain there, so that the user information will be dipsplayed when searched on their name. No worries! there is a way!!

Disable 'my site' and enable 'personal features' & 'manage user profiles'
  1. Go to the ssp personalization permissions page ( Sharepoint Central Admin -> ssp-> service provider -> User Profiles and My Sites ->Personalization services permissions)
  2. Check the user name that you want to disable the 'my site' option. In this case all the users( NT Authority\Auth users)
  3. Click on 'modify permissions' and un select the 'Personal site' right.
  4. Thats it! Now, 'my site' link on all the pages is disabled for the 'NT Auth\Auth users'.
  5. Check the 'Manage User Profiles' and 'Personal Features' rights. Manage user Profiles right will allow the user to have 'My Profile' . Personal Features right will allow the user to enjoy the 'my links' .

So far, we are done with disabling the 'my site' feature. Now lets look at the 'my links' and 'my profile' links. 'My Links' link is on every page. Fine! even the 'Add Links' link within the my links works very fine. But there is a bump on the 'modify links' link. You will get displayed with an as usual un detrmining confused sharepoint error : 'Un Expected Error'. To view the actual error, modify the web.config file located at the 'c:\intepub\wwwroot\wss\virtual dir\your web app port/web.config. modify the config file to set some boolean flags.. false to true! Do it only on Dev/QA servers. Enabling the below debugging option on production server could result in server's performance.

<configuration>
<SharePoint>
<SafeMode CallStack="true" />
</SharePoint>   
<system.web>   
  <customErrors mode="Off" /> 
   <compilation debug="true" />   
 </system.web>   
</configuration>

Just save the file. No IISRESET needed.
After the above changes the error you see is 'Object reference not set to an instance of an object. at Microsoft.SharePoint.Portal.MySiteMapProvider.get_Home()'

The above error occured because the out of the box 'modify links' points to http://mysitehost/_layouts/MyQuickLinks.aspx .
'my site host' in the above URL will point to your my site HOST URL configured for your server. If we look at the URL, the second part '_layouts/MyQuickLinks' is fine.

Even the modify links works if you replace the 'mysitehost' with any existing site name.
http://any existing site1/_layouts/MyQuickLinks.aspx.
So, now we confirmed that there is a problem with the http://mysitehost/. Okay, now open another IE and copy paste the 'http://mysitehost" and see.
URL is redirected to'http://webapp/_layouts/mysite.aspx'. The logic inside the mysite.aspx causes to create or navigate to 'http://mysitehost/personal/userid'. As we all know, this URL is a my site URL for the person 'user id' . In the first section of this article, we prohibited the 'my sites' according to the client's requirement.

So, all we need to do is modify the 'modify links' URL within the 'my links' link.

Now, lets analyze the 'my links' link existing on the page.
How this control is brought to every page? Ans: Masterpage.
Lets look open the master page in the sharepoint designer in a split mode. I love this mode, as it allows me to highlight the code for a corresponding control in the design mode.
Lets go a head and click on the 'my links' link to highlight the code.
The 'My Links' code shows:

<td class="ms-globallinks">     <SharePoint:DelegateControl ControlId="GlobalSiteLink2" Scope="Farm" runat="server"/></td>    

Now, we are confirmed that, My Links is a delegate control with a control Id: GlobalSiteLink2.
And we also know that, delegates are usually regestered in the sharepoint environment by including them in the 'elements.xml' file of a feature. So, if we can re write the delegate with the logic that modifies the URL of the 'modify links' we are set!

make up for the changes:

  1. 'My site' is a feature, thats added to sharepoint and available at the "C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\FEATURES\MySite".
  2. If you navigate to the above file system, you will see two XML files. 'Feature.XML' and 'MySiteFeatureElements.xml'.
  3. Open the 'MySiteFeatureElements.XML' to see the tag:
    <Control Id="GlobalSiteLink2" Sequence="100" ControlSrc="~/_controltemplates/mylinks.ascx"/>
  4. All we need to do is modify the 'mylinks.ascx' to include the new logic or write a brand new '.ascx' and place in the control templates folder available at the 'C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\CONTROLTEMPLATES'.
    All we need to do is replace the '


    <spswc:mylinksmenucontrol id="MyLinksMenu" runat="server">' with <spswc:<em>yourclassfilename</em> id="MyLinksMenu" runat="server" />


    So lets start writing the actual class and go step by step!

Actual Fix:

Step 1: Create the class to include the logic for the modify links URL.

  1. Open Visual Studio 2005 -> File -> New -> Project -> class library -> Name it as 'ModifyLink'
  2. Add the following code inside the class file
    using System;
    using System.Text;
    using System.Collections;
    using System.Collections.Generic;
    using Microsoft.SharePoint;
    using Microsoft.SharePoint.WebControls;
    using Microsoft.SharePoint.Portal.WebControls;
    namespace ModifyLink{
    public class ExtendedModifyLinks : MyLinksMenuControl
    {
    protected override ArrayList LoadMenuItems()
    {
    ArrayList myArray = base.LoadMenuItems();
    MenuItemTemplate myMenu = (MenuItemTemplate)(myArray [myArray .Count - 1]);
    myMenu.ClientOnClickNavigateUrl = SPContext.Current.Site.Url + "/_layouts/MyQuickLinks.aspx";
    myMenu.ClientOnClickScript = "window.location='" + SPContext.Current.Site.Url + "/_layouts/MyQuickLinks.aspx'";
    myArray .RemoveAt(myArray .Count - 1);
    myMenu.Add(myArray );
    return myMenu;
    }
    }
    }
  3. In the above code, we copied the last link within the 'my links' link and modified it to use a new URL. Once the duplicated array item is ready, we replaced that with the exisiting Menu item in the Array.
  4. Strong name the project and Build. Copy the oupt put dll to 'GAC' and 'C:\Inetpub\wwwroot\wss\VirtualDirectories\80\bin' folder.
  5. iisreset.

Step 2: Create the custom '.ascx' delegate control

  • Go to "C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\CONTROLTEMPLATES" folder.
  • Copy the "MyLinks.ascx" and paste in the same folder. Rename the "Copy of MyLinks.ascx" to 'ModifiedMyLinksControl.ascx'
  • Modify the ascx to use the above class assembly dll.
    Replace the below line:
    <%@ Register Tagprefix="SPSWC" Namespace="Microsoft.SharePoint.Portal.WebControls" Assembly="Microsoft.SharePoint.Portal, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

    with
    <%@ Register Tagprefix="SPSWC" Namespace="YourControlClassNamespace" Assembly="YourControlClassAssemblyName, Version=<version>, Culture=neutral, PublicKeyToken=yourToken<keyToken>" %>




    In my case, it is:


    <%@ Register Tagprefix="SPSWC" Namespace="ModifyLink" Assembly="ModifyLink, Version=1.0.0.0, Culture=neutral, PublicKeyToken="123rrdfert423"%>
  • Also, replace the below line

    <SPSWC:MyLinksMenuControl id="MyLinksMenu" runat="server" />




    With
    <SPSWC:YourControlClassName id="MyLinksMenu" runat="server" />






    In my case, it is:
    <SPSWC:ExtendedModifyLinks id="MyLinksMenu" runat="server" />
  • Step 3: Writing the feature:
    1. Go to the My site feature in the Features folder:
      C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\FEATURES\MySite
    2. Backup the existing xml files(copy the two existing xml files: feature.xml and MySiteFeatureElements.xml and paste in the same folder)
    3. Do not touch the feature.xml
    4. Modify the 'MySiteFeatureElements.xml' file to:
      <Elements xmlns="http://schemas.microsoft.com/sharepoint/;
      <Control Id="GlobalSiteLink1" Sequence="100" ControlSrc="~/_controltemplates/mysitelink.ascx" />
      <Control Id="GlobalSiteLink2" Sequence="100" ControlSrc="~/_controltemplates/ModifiedMyLinksControl.ascx"/>
      <Control Id="ProfileRedirection" Sequence="100" ControlSrc="~/_controltemplates/mysiteredirection.ascx"/>
      </Elements>
    5. Save the 'MySiteFeatureElements.xml' .

    install the Feature to a server:

    1. STSADM -o installfeature -filename MySite\feature.xml
    2. If you have 'my site' feature already installed on the server,
      you can do a -force to overwrite the site feature.
      STSADM -o installfeature -filename MySite\feature.xml -force

      for some reason, the -force did not work for me. So I un istalled the feature and re installed.
      to un install: STSADM -o uninstallfeature -filename MySite\feature.xml
    3. As this 'my site' feature is scoped as 'farm' level, need not to activate at a site collection level.
    4. If you think, changing the my site feature directly causes a problem, you can create a new feature( add a new folder inside the 'features' folder and copy paste the 'feature.xml' and elements.xml')
    5. Now the 'modify links' link will target to a new location.

    Monday, April 21, 2008

    The trial period for this product has expired errror while enabling the publishing feature

    OPtion1:

    • If you install MOSS 2007 on a Domain Controller, using publishing feature will give you the error: "The trial period for this product has expired."

    You need to install this patch to fix the problem (link will start the download):
    http://download.microsoft.com/download/b/1/a/b1a6dceb-92a3-4808-8dac-b4e40c90ce00/StandaloneDCWorkaround.msi

    After instllaing patch, reset IIS and then run sharepoint wizard.

    Some times, after entering the MOSS Enterprise key -> iisreset and even rebooted will give the adverse coz, when you setup a basic install, Central Admin app pool will run as Network Service instead of farm account. Network Service do not have the capabilities to license the product.

    Fix: Change the app pool, right click and recycle the app pool.

    Option 2:
    • Due to McAfee Antivirus. No Doubt, McAfee and Micosoft Sharepoint Server 2007 is a perfect combination. But some times, If you have installed McAfee antivirus, the auto update will prompt you to install some updates on the MOSS Box, like the McAfee poralshield update. This portal shield update is a Hotfix that is supposed to set the Sharepoint box with some extra security. Some times you endup installing this update in a failure or you may click 'cancel' on the update install accidentally . The McAfee Portal Shield will fail due to various reasons internally also. Because the installation of the hotfix failed, it tries to set the bug to invalidate the key.

    Fix: Install the McAfee updates properly. If you can not install successfully, make sure that the perticular update is removed successfully :)

    Thursday, March 27, 2008

    Access to a sharepoint publishing site

    Access Permissions to a sharepoint publiching site are different from the Team site.

    Irrespective of whatever site access persmissions given to a publishing site, user can not see the pages until he/she are given at least 'read' permission to the 'masterpage' gallery.

    So, even a full control user to the whole site, if not added to the 'master page' gallery, gets access denied error.

    Adding a user to the master page gallery:
    Site Actions -> Manage Content and Structure -> mouse hover on the masterpage gallery -> context menu -> Edit -> Properties -> Permissions for this gallery -> New.

    If the user is a visitor, allow read permissions on the masterpage gallery.
    IF the user can create the publishing pages, allow the 'Designer' access.
    If the user can delete the gallery items, allow full control.

    Monday, March 10, 2008

    Can not create page from the list controls

    Deployment of content types via feature is bit tricky. Publishing content types for WCM are different in their way. They are special coz lots of publishing elements, such as "Pages" doc lib and page layouts.
    When I deployed the content types using the features, I was redirected to "UploadPage.aspx" page, not to "CreatePage.aspx".Coz, I did not mention the "CreatePage.aspx" template pages explicitly. So, you loose the create page functionality when invoked from the list tool bar menu. Any how, CreatePage.aspx will work if created from the 'Actions' menu.
    Below is the code to add the reference to "CreatePage.aspx" template explicitly :
    <ContentType
    ID="0x010100C568DB52D9D0A14D9B2FDCC96666E9F2007948130EC3DB064584E219954237AF3900<GUID>" Name="my Publishing Content Type" Group="my Publishing Content Type" Description="Content Type inherited from Publishing Page" >
    <FieldRefs>
    <FieldRef ID="{<GUID>}" DisplayName="Title" Name="Title" Sealed="TRUE" />
    <FieldRef ID="{<GUID>}" DisplayName="Description" Name="Comments" />
    </FieldRefs>
    <DocumentTemplate TargetName ="/_layouts/CreatePage.aspx"/>

    </ContentType>

    If you would like to enable this content type to be available only for the specified doc libraries/lists, add the below:
    <ContentTypeBinding    
    ContentTypeId="LIST TO ENABLE " ListUrl="URL"
    />

    This Page has been modified since you opened it. You must open the page again

    You get the error, when you place custom .aspx pages in the "Pages" Doc Library of a publishing site.
    MOSS Publishing feature has special meaning for "Pages" doc lib. If you intend to change it from the out of the box by writting a code in the .aspx pages in the "Pages" doc lib. Even if you place a simple Content Editor Webpart, it tries to change the "Microsoft.SharePoint.Publishing.PublishingLayoutPage" name space to "Microsoft.SharePoint.Publishing.PublishingLayoutPage". The error message says this change in a brief!

    To avoid this, follow the workarounds specified below.
    If you are confused or naive to Sharepoint Designer, simply copy the .aspx custom developed pages from the "Pages" doc lib to the area directly under the site folder. Good Luck!

    While trying to edit the pages created in the publishing sites, you get this error.
    When you use publishing in Sharepoint, you have a pages library with pages that have a page layout. These page layouts need to inherit from Microsoft.SharePoint.Publishing.PublishingLayoutPage and not from Microsoft.Sharepoint.Pages.WebpartPages.
    You need to insert the pages in the pages library with a Page Layout.

    The generic ONET.XML looks like this:

    " Module Path="" Url="$Resources:cmscore,List_Pages_UrlName;" Name="DefaultBlank
    File Url="default.aspx" Level="Approved" Type="GhostableInLibrary
    Property Name="Title" Value="Default
    Property Name="ContentType" Value="$Resources:cmscore,contenttype
    "

    You have to add a property to the page you are adding. That property is called ‘PublishingPageLayout’ and should have the page layout you want to use as the value.
    The page layout that you want to use should inherit from Microsoft.SharePoint.Publishing.PublishingLayoutPage, and most reside in the masterpages gallery of your site collection.

    ONET.XML, after modifying:

    "
    Module Path="" Url="$Resources:cmscore,List_Pages_UrlName;" Name="DefaultBlank
    File Url="default.aspx" Level="Approved" Type="GhostableInLibrary

    Property Name="PublishingPageLayout" Value="~SiteCollection/_catalogs/masterpage/WelcomeLinks.aspx, ~SiteCollection/_catalogs/masterpage/Contact.aspx
    Property Name="ContentType" Value="$Resources:cmscore,contenttype_pagelayout_name;">


    "

    If you have the page display problem after installing SP1, follow the instructions below:

    Replace

    Page language="C#" Inherits="Microsoft.SharePoint.Publishing.PublishingLayoutPage, Microsoft.SharePoint.Publishing,Version=12.0.0.0, Culture=neutral,PublicKeyToken=71e9bce111e9429c" metarogid="SharePoint.WebPartPage.Document" meta:webpartpageexpansion="full"
    with

    Page language="C#" Inherits="Microsoft.SharePoint.Publishing.TemplateRedirectionPage, Microsoft.SharePoint.Publishing, Version=12.0.0.0,Culture=neutral,PublicKeyToken=71e9bce111e9429c" metarogid="SharePoint.WebPartPage.Document" meta:webpartpageexpansion="full"






    Wednesday, March 5, 2008

    Create a site template from a publishing site

    Publishing sites never allow you to save the site as template to be used in the sub site creation.
    to allow this, you need to switch the publishing feature off -> save the teplate -> swtch on oagain!

    or else you can append the following URL to force the publishing site to get the site template property.

    http://your publishing site name/_Layouts/AreaTemplateSettings.aspx.

    Some times the templates created by following the above logic will go weird! Even if you save the template from SharePoint Designer it will go wild and do strange things!
    Then you should create site definitions (..\web server extensions\12\template\SiteTemplates) .

    Saturday, February 2, 2008

    Modifying the Search results URL in sharepoint 2007 searchresults.aspx

    How to remove something (the port) from the URL as returned in the search results (searchresults.aspx):

    Starting with the Infrastructure update, the following behavior can be encountered when searching for people:
    The port (usually 80) is appended to the URL of the location for each result, resulting in error for all the internet facing personal sites.
    For example, imagine you published your my site location in Alternate Access Mappings at : http://mysites.mydomain.com to be accessed from the intranet and https://mysites.mydomain.com to be accessed from the internet.

    When you are searching for a user when logged on from the internet side of things, you will receive the results pointing to https://mysite.mydomain.com:80/Person.aspx?GUID... which will throw an error upon accessing (page not found).

    If you want to overcome the issue (eg, you are looking for a quick fix) here's what you can do:

    Go to your search center with tabs and search for something, just to get to the people results page.
    Edit the page and modify the People Search Core Results web-part.
    Click on the XSL Editor button to get to the XSL style sheet applied to the resultset.
    The URL for each result is under the following section:














    <!-- This template is called for each result -->

    <xsl:template match="All_Results/Result">
    <xsl:variable name="id" select="id"/>
    .....
    here ,

    replace <xsl:variable name ="url" select ="url"/>
    line with:


    <xsl:variable name ="temp" select ="url"/>
    <!-- We put the url value from the resultset in temp variable -->

    <xsl:variable name="url">
    <!-- This will be the value used in the xsl from now on in this section as $url -->

    <xsl:choose>
    <xsl:when test="contains($temp,':80')">
    <!--We check temp variable for the occurrences of string :80-->
    <xsl:value-of select ="concat(substring-before($temp,':80'),substring-after($temp,':80'))"/>

    <!--We remove from temp variable the occurrences of string :80-->
    </xsl:when>

    <xsl:otherwise>
    <xsl:value-of select ="$temp"/>
    <!--If we did not find the :80 we will retain the default value (url) as defined above-->

    </xsl:otherwise>
    </xsl:choose>
    </xsl:variable>

    ....

    So from now on, wherever we will use $url we will have the translated version of the url returned in the resultset
    eg. for https://mysite.mydomain.com:80/person.aspx?GUID....... the result would be https://mysite.mydomain.com/Person.aspx?GUID.......

    Of course you will also need to play with the Search High Confidence Results web Part to Edit it accordingly.
    The place where you need to replace the url is :

    <xsl:template match="All_Results/HighConfidenceResults/Result">
    <xsl:if test="$DisplayHC = 'True' and $IsFirstPage = 'True'" >
    <xsl:variable name="prefix">IMNRC('</xsl:variable>
    <xsl:variable name="suffix">')
    </xsl:variable>
    <xsl:variable name="url" select="url"/>
    <xsl:variable name="id" select="id"/>

    replace <xsl:variable name ="url" select ="url"/> line as above

    Here are some additional references on how to edit, and tune the search results to fit your company needs:

    http://msdn.microsoft.com/en-us/library/ms584121.aspx
    http://msdn.microsoft.com/en-us/library/ms256069(VS.85).aspx

    Monday, January 7, 2008

    Scaling SharePoint 2007 Storage Architecture in a brief!

    Well.. Happy anniversary to Sharepoint 2007!

    Another day and another thought! Time to discuss the gotchas for the administrators!!
    Great challenge to any administrator is to Plan the available resources such that the resources are used for optimum solutions and overhead! And I am not an exceptional. So lets walk through the strategies that turns the effective planning in the reality!!

    Sharepoint and content database

    All the bulk data in all the site collections that comprise the portal instance is stored in the SharePoint Content databases. So SharePoint content databases grow very rapidly when used in file share replacement/document imaging system scenarios. This gives the headsup to consider the growth and overhead factors when determining how much content will eventually be stored in a given content database. You must be able to ensure that one site collection cannot use so many resources that other site collections can no longer function.

    Windows SharePoint Services allows you to specify quota for site collections, so that you can manage your site and server resources. When you are planning the taxonomy and information architecture of your sites, a good amount of effort and thought should be put into Site Quotas.

    Site Quotas are a key component for SharePoint Administrators to be able to properly manage and administer data restrictions on your site collections. SharePoint stores site content within a SQL Server database. Therefore, if you want to optimize SharePoint storage architecture, you have to focus on SQL Server. fortunately, Microsoft provides several Performance Monitors you can use with SQL Server. Great!
    The content/data in the Recycle Bin is also included in the Quota space (it’s part of the site).

    Site Collection Quotas and Quota templates are managed in Central Administration Microsoft suggests that the optimal maximum content database size should be 50GB. They alsorecommend that for most SharePoint implementations, the solution should not include any contentdatabases larger than 100GB. This is commonly referred to as the “100GB content database sizelimitation”. In fact, this is not a true limitation but rather a recommendation. SQL Server databases have beenscaling far beyond 100GB for years now.

    Practically speaking, the recommendation is based primarilyon two significant factors:

    1. Service Level Agreement (SLA) requirements for a given organization may dictate that backupoperations for the SharePoint databases must be executable in a limited amount of time. Thesize of the content databases will have a direct impact on how long it takes to execute thatbackup.

    2. The storage subsystem must be robust enough to handle the disk I/O requirements of theSharePoint solution that it serves.

    As long as a given organization is able to mitigate these two considerations, then the contentdatabases can be allowed to grow. Real world implementations have seen successful SharePointdeployments that have implemented database sizes of 100GB, 150GB, 200GB, 250GB, 300GB,350GB and 400GB. In order to mitigate the SLA requirements, a solution might employ a high speed disk-to-disk backupsolution, database mirroring, or database log shipping to a disaster recovery site.

    Some tips and tricks to mitigate:

    1. Add tempdb(space for the intermediate data) data files such that the number of data files equals the number of CPU corespresent in the SQL Server machine. Each data file (primary .mdf and additional .ndf(s)) shouldbe equal in size.
    The size of each data file can be calculated using this formula:

    [MAX DBSIZE (KB)] X [.25] / [# CORES] = DATA FILE SIZE (KB)

    2. once the raw file storage quantities are determined, the following formula may be used to estimate databaseoverhead:

    Database Overhead Formula:
    Low: 1.2 * [Raw Storage Size] = ContentDB Size
    High: 1.5 * [Raw Storage Size] = ContentDB Size

    3. Use the following formula to calculate how much disk space needed for the search database:

    GB of disk space required = Total_Content_Size (in GB) x File_Size_Modifier x 4
    where File_Size_Modifier is a number in the following range, based on the average size of the files inyour corpus:

    • 1.0 if your content consists of very small files (average file size = 1KB).
    • 0.12 if your content consists of moderate files (average file size = 10KB).
    • 0.05 if your content consists of large files (average file size 100KB or larger)

    4. Place the content database file(s) on RAID 10 logical unit(s) if at all possible.

    5. Place the search database log file on its own logical unit.

    Some SQL gotchas:

    Move tempdb
    After executing this script and restarting SQL Server, the tempdb data and log files willbe initialized in the new location.

    USE master
    GO
    ALTER DATABASE tempdb MODIFY FILE (NAME = tempdev, FILENAME = ‘[New data folderpath]\tempdb.mdf')
    GO
    ALTER DATABASE tempdb MODIFY FILE (NAME = templog, FILENAME = ‘[New log folderpath]\templog.ldf')
    GO
    (Don't forget to Restart SQL Server)