Tuesday, November 1, 2011

Creating a Wiki Page template For SharePoint 2010 Foundation

Introduction

As I have ever written several time in my previous posts, one of the severe limitation of SharePoint Foundation is that the Wiki Pages are based on a single template wkpstd.aspx located at

C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\TEMPLATE\DocumentTemplates

If you try to add a wiki page programmatically to a wiki page library of a SharePoint Foundation team site and you want it to be ghosted you must use the method SPFileCollection.Add with this signature :

 Add(String, SPTemplateFileType)

And pass the reference of the wiki page template wkpstd.aspx to the SPTemplate parameter. If you use any other signature, you will be able to add a wikipage, but it will be unghosted.

I am now going to show you a very amazing workaround to use another template than the wkpstd.aspx one and will process in  two steps. First I will demonstrate it so as you can easily understand its principle then I will provide a programmatic way of doing it.

Demonstration

Start creating your new template by duplicating the wkpstd.aspx and rename it wkpcustom.aspx, then perform a little operation of customization in order each page based on this new template can tell its name :

In the page directive section add the namespace System.Diagnostics because the wiki pages will tell their nam in the debugView...

<%@ Import Namespace="System.Diagnostics" %>

Then, at the top of the PlaceHolderMain section paste this code:

protected override void OnPreInit(EventArgs e)
{
     base.OnPreInit(e);

    Debug.WriteLine(SPContext.Current.File.Name);
}

 

Then, we are going to prepare a feature to reference this wkpcustom.aspx file in a SharePoint Foundation wiki page library.

Assume we call the feature

 Provisioning.SPF_WikiPages

Here is the feature.xml code:

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

<Feature Id="00BFEA71-2062-426C-90BF-714C59600AAA"

Title="Adding pre populate wiki pages"

Description="This feature will add pre-populate wiki pages to the site pages wiki library of this site"

Version="1.0.0.0"

Scope="Web"

Hidden="false"

DefaultResourceFile="core"

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

  <ElementManifests>

    <ElementManifest Location="elements.xml" />

  </ElementManifests>

</Feature>

And this is the xml code of the elements.xml file

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

  <Module Url="SitePages" >

    <File Url="wkpcustom.aspx" Type="GhostableInLibrary"></File>

  </Module>

</Elements>

 

Last, a screen shot of the Provisioning.SPF_WikiPages feature folder

 

Then, install the feature and activate it for one of the team site of your Farm and you will have a reference to your page in the site pages library of this team site.

 

You can see a reference to the wkpcustom file located in the feature folder on the server

 

And because this file was provisioned by a feature, although there is in line code in it, if you display the wiki page using this file, it will work, the code will run and will write the name of the page in the debugview.

 

But, wait a minute, this file is already a template. It is a template for just one page within the site pages library but it is exactly like the wkpstd.aspx for the other pages. So assume we could have several pages within the library based on this file we would have created a new template. I see some of you smiling...

You have understood... It is what we are going to do now...

Now is the time to use another workaround I have already shown in a previous post to open our library in explorer mode.
So switch to shared documents library, open it in explorer mode, then using the explorer folder navigation go back to the site pages library but in explorer mode now

 

Then rename the page in "page 01.aspx"

 

then go back to the site pages library within the SharePoint UI. You will notice that the page is renamed and if you displayed it, its name in the debugview has changed too. While renamed, the page remains in its ghosted state and linked to the "template".

 

Now deactivate the feature, then reactivate it and you will have a new page wkpcustom.aspx beside the "page 01.aspx" and the two pages are linked to the same file on the server, so if we display one then the other, debugview will trace the two names based on the code of an unique file on the server: we have created our first custom template for a wiki page library in SharePoint Foundation!

 

Now we have done the demonstration we just have to find the way to do it programmatically:

Coding the sequence

this applicative page called from your site will provision 9 pages in your site page library pointing on the same unique template wkpcustom.aspx located in the feature folder. If you modify the file in the folder, you will modify the 9 pages

 

<%@ Page Language="C#" AutoEventWireup="true" Inherits="Microsoft.SharePoint.WebControls.LayoutsPageBase"

    DynamicMasterPageFile="~masterurl/default.master" %>

 

<%@ Assembly Name="System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" %>

<%@ Import Namespace="Microsoft.SharePoint" %>

<%@ Import Namespace="Microsoft.SharePoint.Administration" %>

<%@ Import Namespace="System.Text" %>

<%@ Import Namespace="System.Linq" %>

<%@ Assembly Name="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

 

<asp:content id="PageHead" contentplaceholderid="PlaceHolderAdditionalPageHead" runat="server">

</asp:content>

<asp:content id="Main" contentplaceholderid="PlaceHolderMain" runat="server">

 

<script language="C#" runat="server">

 

    protected override void OnLoad(EventArgs e)

    {

        base.OnLoad(e);

 

        SPWeb myWeb = SPContext.Current.Web;

        myWeb.AllowUnsafeUpdates = true;

 

        for (int i = 1; i < 10; i++)

        {

 

            if (myWeb.Features[new Guid("{00BFEA71-2062-426C-90BF-714C59600AAA}")] != null)

            {

                myWeb.Features.Remove(new Guid("{00BFEA71-2062-426C-90BF-714C59600AAA}"));

            }

 

            myWeb.Features.Add(new Guid("{00BFEA71-2062-426C-90BF-714C59600AAA}"));

 

            SPList myList = myWeb.Lists["Site Pages"];

 

            SPListItem myItem = null;

 

            SPContext.Current.Web.AllowUnsafeUpdates = true;

 

            foreach (SPListItem anItem in myList.Items)

            {

                if (anItem.Name == "wkpcustom.aspx")

                {

                    myItem = anItem;

                }

            }

 

            string destinationUrl = myWeb.Url + "/" + myList.RootFolder.Url + "/" + "Wiki_page0" + i + ".aspx";

            myItem.File.MoveTo(destinationUrl);

            myItem.File.Update();

 

            myWeb.Features.Remove(new Guid("{00BFEA71-2062-426C-90BF-714C59600AAA}"));

        }

 

        lbl1.Text = "Your files has been provisionned successfully...";

    }

 

</script>

 

<asp:Label runat="server" ID="lbl1" ></asp:Label>

 

 

</asp:content>

<asp:content id="PageTitle" contentplaceholderid="PlaceHolderPageTitle" runat="server">

 

Provisioning Team Site Wiki Pages

 

</asp:content>

<asp:content id="PageTitleInTitleArea" contentplaceholderid="PlaceHolderPageTitleInTitleArea"

    runat="server">

 

Provisioning Team Site Wiki Pages

 

</asp:content>

 

 

Here are the screen shots of the applicative page after its provisioning job is finished

 

and the site pages library with the 9 new pages

 

And if I call the 9 pages, each of them will tell me its name.

 

And now, I have changed the instruction of the name displaying in the template, and I have called back the 9 pages and here is the result.

 

Have a lot of fun with that!

 

Monday, October 24, 2011

Configuring SharePoint 2010 Foundation for Internet-facing publishing

Introduction

I am starting a set of posts regarding the ability of SharePoint 2010 foundation to be used to build Internet-facing web sites. In this one we are just going to perform configuration and creation operations so as we can obtain a SharePoint Foundation site collection that can be used to publish content on the Internet and therefore, available for anonymous users.

Business benefits - The "why" part of the post

In SharePoint 2007 the Internet-facing publishing was rather based on the use of the publishing part of SharePoint, its CMS.

However, the team sites that were a part of the collaboration area of SharePoint 2007 are now with the new wiki pages of SharePoint 2010 a way to help people to publish formal content. The team sites are now described in the SharePoint 2010 documentation as a solution to encourage one-to-many communication and also a solution to offer a structured exchange of information.

Therefore the team sites of SharePoint Foundation are now mature enough to be used as a base to build Internet-facing web sites and are a new and more cost effective opportunity offered by SharePoint 2010 to publish content on the Internet. The free SharePoint Foundation team sites can be now seen as a severe competitor to the licensed SharePoint CMS!

For further information, see the Microsoft documentation:

Comparison of Enterprise Wikis with Team Sites

Plan Internet presence sites (SharePoint 2010 Foundation)


And this Ted Pattison's video:

Sites as Collections of Pages
(See how Sites in SharePoint 2010 just become a collection of pages. Unlike before pages now play a key role in the structure of a site... )



I have just found elements of comparison when considering SharePoint Server 2010 Publishing Sites vs. SharePoint Foundation 2010 Sites:

SharePoint Server 2010 Publishing Sites vs. SharePoint Foundation 2010 Sites

After requirements gathering is complete, first decide whether to base the website on Microsoft SharePoint Foundation 2010, or on a server running Microsoft SharePoint Server 2010 with the Publishing Features enabled. Publishing sites are built on SharePoint Foundation, and there are many advantages to building engaging Internet-facing websites with publishing sites. Some of the benefits of creating a brand with SharePoint Server publishing sites and SharePoint Foundation sites include the following:

Enables content authors to create webpages with a more robust rich-text editing experience than SharePoint Foundation sites offer.

Includes master pages that target publishing sites and that use specific code assemblies that take advantage of publishing Features.

Easier control of web navigation from the web UI, and more options are available to the designer.

Uses the Web UI to easily change a master page and to apply master pages to all subsites below the current site.

Uses page layouts to create templates at the page level. Uses text layouts to accomplish a form of simple page layout. Text layouts are not configurable.

Use the $SPUrl token to target HTML assets with URLs that are relative to either the site collection ($SPUrl;~sitecollection/) or site root ($SPUrl:~site/)

source: Real World Branding with SharePoint 2010 Publishing Sites

Audience

I will avoid using development operations in this first post in order it can be useful to system administrators. Of course it is also targetted for developers so as they can configure their development machine, but they won't have to launch Visual Studio here.

1 - Extending an existing SharePoint Foundation Web Application

Assume you have created a SharePoint Foundation web application using NTLM authentication (that is the default mode).
Go to the SharePoint 2010 Central Administration of your SharePoint Farm, click the "Manage web applications" link then on the displayed list of the available web application select the one you want to open to anonymous users.

The buttons of the SharePoint 2010 ribbon are now  usable, so click on Extend.
The Extend pop-up appears.

Type the name of the new web application
Type 80 for port
Define a host header
Select Allow Anonymous because we are planning anonymous access
For the zone, choose Internet, because we plan to extend the existing web application for an Internet access.

So as you will obtain the following screen shots

 

 

Then,  click the "OK" button to create the web application.
Nothing has changed in the web application list, but if you navigate to the Alternate Access Mappings page of the central administration (in the System Settings section), then click on the "Edit Public Zone URLs" link and select the extended web application you will notice taht the zone was properly created.

 

 

You can also check in IIS7 that the IIS web site for the Internet zone is now available

2 - Testing the anonymous acces

As we have defined previously a custom host header for our Internet site we have to modify the host file of our development machine in order to be able to acces the site as an anonymous user.
So open the hosts file of your machine located at :

C:\Windows\System32\drivers\etc

and add the following entry:

 127.0.0.1       www.mycompany.com

Now open a browser and browse to this url. You access your SharePoint team site as an anonymous user and simulate an Internet acces.

if you cannot access to the site with an anonymous access, browse to the http://www.mycompany.com/_layouts/setanon.aspx page, you will be prompted for authentication, use the site coll administrator to authenticate in NTLM mode, switch anonymous access to Entire site, click OK (in the screen shot, url is wrong, sorry).

 

If you select Lists and libraries, anonymous users will be able to view items only for those lists and libraries that have enabled permissions for anonymous users.

However how interesting this option is, it will force administrator to break inheritance for each lists for those they want to grant access for anonymous users. You will also notice that for those lists, the SharePoint Forms pages are also accessible to anonymous users. For example, if you grant access to anonymous users for the site pages library of a Foundation team site, anonymous users might be able to get to
http://www.mycompany.com/SitePages/Forms/AllPages.aspx.

Typically you don't want this, so how do you prevent anonymous users from accessing these pages?   
In SharePoint Server, where the publishing features are available we would activate the lockdown feature especially provided by Microsoft for avoiding this problem.  

By the way, It is amazing to think to activate within SharePoint Foundation the lockdown feature which was formerly reserved to the SharePoint CMS .
Yes and no.
Now the team sites must be seen as a collection of pages. They get closer to the SharePoint CMS a lot.
On this subject you should watch the Ted Pattison's video (See how Sites in SharePoint 2010 just become a collection of pages. Unlike before pages now play a key role in the structure of a site.).



Updated 2011 october 26th

3 - An alternative to the lockdown Feature

Unfortunately, this feature is not available for SharePoint foundation. So I made an adaptation for WSS 3.0 and SharePoint Foudation 2010 that you can download as a SharePoint solution (.wsp) on Codeplex:

Custom lockdown feature for wss 3.0 and SharePoint 2010 Foundation

If you want to use it, download the .wsp and deploy it. It will be globally deployed anyway because the feature handler .dll will be placed in the GAC.
Then you should not need to install the feature because it will be automatically installed at deployment time, but if the automatic  installation had failled, you could install it by excuting this within a command prompt:

stsadm -o installfeature -name viewformpageslockdowncustom

then activate the feature for your site collection with this other instruction:

stsadm -o activatefeature -name viewformpageslockdowncustom -url http://www.mycompany.com

But, beacause we already have anonymous access enabled, we need to go disable it, then enable it again. Go to the _layouts/setanon.aspx page, switch anonymous access off, click OK, then go back and set it to entire site, then click OK.

Anonymous users should now get an authentication prompt when they try to navigate to a form page. For example,
http://www.mycompany.com/SitePages/Forms/AllPages.aspx.

 

 

4 - Setting custom error page for error 401 (forbidden) within Sharepoint 2010

(The following section is dedicated to Sharepoint 2010 since you will not find the following xml tags in the web.config of wss 3.0.)

Now we are going to do an amazing thing. We are going to change the web.config file of the web application corresponding to the Internet access so as anonymous user won't be prompted anymore for authentication if they try to acces to an unauthorized url but be redirected on a custom 401 error page within the site.

So first go to your site with at least contributor permissions by using NTLM access and create a custom 401 error page in the site pages library of your site. Assume we call it unauthorized so as its url will be http://www.mycompany.com/sitepages/unauthorized.aspx. Type a meessage of access denied and save the page.

Then, open the web.config file of the Internet zone web application and locate the handlers end tag within the system.webSever and paste the following httpErrors sequence.

     </handlers>
        <httpErrors errorMode="Custom" existingResponse="Auto">
            <remove statusCode="401" />
            <error statusCode="401" prefixLanguageFilePath="" path="/sitepages/unauthorized.aspx" responseMode="ExecuteURL" />
        </httpErrors>
  </system.webServer>

 After restarting your application pool by reloading a page of your site with anonymous acces, you will notice an amazing thing: each time an anonymous user will try to access to a non authorized ressource, instead of being prompted for an NTLM authentification, he will be redirected to the custom 401 error page of your site and he will still have your site navigation links available and be able to keep browsing.

And the most amazing is you will have the same result while clicking the sign in link.
So of course don't do that if you plan to use an Internet access for contributing on your site or for administrating it...

And don't forget that this will have an impact on the whole web application since we have modified the web.config, so it won't be possible to obtain a different behaviour for another site collection within this web application.

 The next screen shot show my 401 unauthorized custom error page after having clicked the Sign in link.

It is all that we can do for now by just performing configuration operations.
Of course, don't forget to modify the navigation within the SharePoint 2010 UI to hide all the links that could lead to an access denied for anonymous users. In short, you should let only the links pointing on a subsite, a Site Page or a specific document.


In the next post, we are going to use Visual Studio to start customizing our site...

5 - Aknowledgements

Thanks to :

Nick whose article helped me for custom errors, I have just noticed that he also lives and works in Montreal...

Tyler Butler of the ECM team blog who was by his publications of a big help in the realization of my projects for the internet and who made me discover the existence of the lockdown feature...

Ted Pattison for his video which opens many new horizons regarding the use of SharePoint 2010. I will publish more about it someday...

 

 

Saturday, October 22, 2011

Creating a custom document library for SharePoint 2010

Introduction

It seems that it is not that obvious to find clear documentation to create a custom document library for SharePoint 2010.
Most of the Microsoft documentation is now based on using Visual Studio 2010 and are more focused on the lists than on the document libraries.

By the way document libraries in SharePoint 2010 seems to has become lists, but the lack of documentation regarding the creation of custom lists remains anyway, so after having perform some successful trials I have decided to publish a step by step guide.

Functional benefits

I won't spend much time in this post explaining the functional benefits of creating a custom document library because I plan to publish soon a new post explaining the difference between a custom list and a list instance and the functional benefits and drawbacks of each. But think carefully before creating a custom document library.
I have created one in a previous project for MOSS 2007 and had serious problems when migrating to SharePoint 2010.
In most of the cases, a list instance is enough so if it is possible, avoid creating a custom list or document library. In a general way, avoid as much as possible to create custom CAML definitions for sites, lists and so on... 

Required steps for creating a custom SharePoint 2010 document library

1 - Duplicate the native DocumentLibrary feature
2 - Change the attributes of the Feature tag of the Feature.xml file
3 - Change the attributes of the ListTemplate tag of the DocumentLibrary.xml file
4 - Rename the DocLib folder located in the DocumentLibrary folder
5 - Install the feature
6 - Activate the feature for a specific site
7 -Test

Detailed operations

1 - Duplicating the native DocumentLibrary feature

Locate the folder of th DocumentLibrary feature located in: C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\TEMPLATE\FEATURES
Copy and paste the folder and rename it. Assume we rename it MyCompany.MyCustomDocumentLibrary.

 

 

2 - Changing the attributes of the Feature tag of the Feature.xml file and adding some more attributes

Open the Feature.xml file with Visual Studio or a text editor, and change these attributes:

ID
Change the ID of the feature. I usually change the last figures by the new type of the list. Assume the new type is 10001 (it is not recommended to use a new type smaller than 10000), the new ID of the feature of my custom document library will be 00BFEA71-E717-4E80-AA17-D0C71B310001.

Title
The title will appear in the UI of SharePoint 2010 in the "Manage Site Features" page (because the attribute Scope is set to Web).

Description
The description will also appear in the UI of SharePoint 2010 in the "Manage Site Features" page (Because the attribute Scope is set to Web).

Hidden
Change the value of the attribute to FALSE in order to see the feature in the "Manage Features" page of your SharePoint 2010 so as you can activate it manually and allow a site administrator to activate it.

Add the following attributes

AlwaysForceInstall="TRUE"
This will avoid having an error at deployment time if you deploy this feature in a SharePoint solution (.wsp file) by retracting, removing the old version of your solution and re-deploying a new one.

ImageUrl
I have created a folder for MyCompany located in the SharePoint 2010 IMAGES folder located at:
C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\TEMPLATE\IMAGES
(I use a part of the SharePoint summit logo because I was speaker at this summit last year in Quebec and plan to be speaker on 2012 at Toronto and Quebec.)

Here is the new xml after the changes has been performed:

<?xml version="1.0" encoding="utf-8"?>
<
Feature Id="00BFEA71-E717-4E80-AA17-D0C71B310001"
                  Title="MyCompany MyCustom Document Library"
                  Description="Allow a custom document library to be created within this site"
                  Version="1.0.0.0"
                  Scope="Web"
                  Hidden="False"
                  AlwaysForceInstall ="TRUE"
                  ImageUrl ="MyCompany/sharePointSummitLogo.jpg"
                  DefaultResourceFile="core"
                 xmlns=http://schemas.microsoft.com/sharepoint/>
                 <
ElementManifests>
                          
<ElementManifest Location="ListTemplates\DocumentLibrary.xml" />
                 </
ElementManifests>
</
Feature>

 

3 - Changing the attributes of the ListTemplate tag of the DocumentLibrary.xml file

Name
This is the important key. This name and the name of the folder where the schema.xml file of the custom library is located MUST be the SAME !
I use customdoclib1

Type
As written before the new type will be 10001. The type can for example be used in a feature that will place a custom button in a document library ribbon so as when you activate the feature for the new button, only the document libraries with the 10001 type will have the new button. Changing the type is one of the good reasons to choose to create a custom document library rather to create a list instance. But it can also cause many problems later for example when migrating to a new version of SharePoint so be careful.
The base type will not be changed, BaseType 1 means the list is a document library...

DisplayName
This name will appear in your SharePoint site in the create page when you want to create a custom document library within your site.

Description
The description will appear in your SharePoint site below the display name in the create page when you want to create a custom document library within your site.

Here is the new xml after the changes has been performed:

<?xml version="1.0" encoding="utf-8"?>
<
Elements xmlns="http://schemas.microsoft.com/sharepoint/">
      <
ListTemplate
          Name="customdoclib1"
          Type="10001"
           BaseType="1"
           OnQuickLaunch="TRUE"
           SecurityBits="11"
           Sequence="110"
           DisplayName="My Company Document Library"
           Description="Create a document library with xyz functionalities"
           Image="/_layouts/images/itdl.png"
           DocumentTemplate="121"/>
</
Elements>

4 - Renaming the DocLib folder located in the DocumentLibrary folder

As written before, the important key is now to rename the folder where the document library schema.xml file is located so as it has the same name than the name attribute of the custom document library template.

So we rename the folder to customdoclib1

 

 

5 - Installing the feature

Now, all we have to do is install the feature so open a command prompt and be sure to have the administrator permissions on the machine. If the stsadm.exe path is referenced in the system variables of the machine you just have to type the following:

stsadm -o installfeature -name MyCompany.MyCustomDocumentLibrary

In order to obtain this screen

 

 

6 - Activating the feature for a specific site

So now, open a site and you should see your feature in the "Manage Site Features" page as shown in the next screen shot.

 

 

Notice that the description filled in the feature.xml file is displayed on the page.
Click the Activate button to enable the custom library creation within this site.

 

7 -Testing

Now if you navigate to the SharePoint 2010 Create pop up using the "Site Actions" menu and clicking "More Options..." then selecting Library in the pop up you will notice that the references to the custom library are actually displayed by the pop up.

Notice that the name and description typed previously in the documentlibrary.xml file are properly displayed.

So type a name for your new custom document library for SharePoint 2010 and check it is correctly provisioned within your site.

 

Well done !!!