Sunday, September 7, 2008

Creating Custom Application Page

Scenario:
You want to write a Custom Application Page for some additional configurations for all of your sites.

Myconfig.ASPX(12/TEMPLATE/Layouts/Client/):


<%@ Assembly Name="Microsoft.SharePoint,[rest of 3-part assembly infomation]"%>
<%@ Page Language="C#" MasterPageFile="~/_layouts/application.master"
Inherits="Microsoft.SharePoint.WebControls.LayoutsPageBase" %>

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

<script runat="server">
protected override void OnLoad(EventArgs e) {
SPWeb site = this.Web;
lblSiteTitle.Text = site.Title;
lblSiteID.Text = site.ID.ToString().ToUpper();
}
</script>

<asp:Content ID="Main" runat="server" contentplaceholderid="PlaceHolderMain" >
Site Title: <asp:Label ID="lblSiteTitle" runat="server" />
<br/>
Site ID: <asp:Label ID="lblSiteID" runat="server" />
</asp:Content>

<asp:Content ID="PageTitle" runat="server" contentplaceholderid="PlaceHolderPageTitle" >
Hello World
</asp:Content>

<asp:Content ID="PageTitleInTitleArea" runat="server" contentplaceholderid="PlaceHolderPageTitleInTitleArea" >
'Hello World' of Application Page
</asp:Content>
Usage:
You can access to the page from any web i.e.
 http://localhost/_layouts/client/myconfig.aspx
or you can also write a CustomAction to access the URL

Extending STSADM Command set

Scenario:
You want to extend STSADM by including a new operation for enumerating all the features for a given site.

Code(GAC):


using System;
using System.Collections.Specialized;
using System.Text;
using Microsoft.SharePoint;
using Microsoft.SharePoint.StsAdmin;

namespace TrainingSamples
{
public class SimpleCommandHandler : ISPStsadmCommand
{
public string GetHelpMessage(string command)
{
return "-url <full url to a site in SharePoint>";
}

public int Run(string command, StringDictionary keyValues, out string output)
{
command = command.ToLowerInvariant();

switch (command)
{
case "enumfeatures":
return this.EnumerateFeatures(keyValues, out output);

default:
throw new InvalidOperationException();
}
}

private int EnumerateFeatures(StringDictionary keyValues, out string output)
{
if (!keyValues.ContainsKey("url"))
{
throw new InvalidOperationException("The url parameter was not specified.");
}

String url = keyValues["url"];

SPFeatureCollection features = null;
SPWeb web = null;

try
{
SPSite site = new SPSite(url);

web = site.OpenWeb();

features = web.Features;
}
catch (Exception e)
{
throw new InvalidOperationException("Error retrieving url '" + url + "'. Please check the format of your url, and ensure that the site exists. Details: " + e.Message);
}

StringBuilder sb = new StringBuilder();

sb.AppendLine("Features at '" + web.Url + "':\n");

foreach (SPFeature feature in features)
{
sb.AppendLine(feature.Definition.DisplayName + " (" + feature.DefinitionId + ")");
}

output = sb.ToString();

return 0;
}
}
}


STSADMCommands.TrainingSamples.xml(12\Config):


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

<commands>
<command
name="enumfeatures"
class="TrainingSamples.SimpleCommandHandler, [full 4-part assembly name]"/>
</commands>



Usage:

stsadm -o enumfeatures -url http://localhost

Saturday, September 6, 2008

Creating a basic Item Event Handler

Scenario:
You want to write an event handler to cancel the deletion of an item from Announcement List ( Type = 104 )

Event Handler Code:


using Microsoft.SharePoint;

namespace TrainingSamples
{
public class DeletingAction : SPItemEventReceiver{
public override void ItemDeleting(SPItemEventProperties properties){
properties.Cancel = true;
properties.ErrorMessage = "Deleting items from " + properties.RelativeWebUrl + " is not supported.";
}
}
}
Feature.xml

<Feature Scope="Web"
Title="Deleting Event Handler"
Id="GUID"
xmlns="http://schemas.microsoft.com/sharepoint/">
<ElementManifests>
<ElementManifest Location="Elements.xml"/>
</ElementManifests>
</Feature>
Elements.xml:

<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<Receivers ListTemplateId="104">
<Receiver>
<Name>DeletingEventHandler</Name>
<Type>ItemDeleting</Type>
<SequenceNumber>10000</SequenceNumber>
<Assembly>DeletingEventHandler, Version=1.0.0.0, Culture=neutral, PublicKeyToken=a26b5449ac4a4cf3</Assembly>
<Class>DeletingEventHandler.DeletingAction</Class>
<Data></Data>
<Filter></Filter>
</Receiver>
</Receivers>
</Elements>


Additional Notes:
This will attach event handler to any list of Type=104. So If you have specific requirements to attach event handler to a particular list only, then go for a Feature Receiver.

Test Case for a Feature receiver

Scenario:
You want to write a test case for the Feature Receiver

Sample Feature Code:

namespace TrainingSamples
{
public class SampleFeatureReceiver:SPFeatureReceiver
{

[SharePointPermission(SecurityAction.LinkDemand, ObjectModel = true)]
public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
if (properties == null)
{
return;
}

SPWeb web = (SPWeb)properties.Feature.Parent;
this.OnActivationCode(web);
}

public void OnActivationCode(SPWeb web)
{
//Code

}
}
}
Sample Test Case Code:
namespace TrainingSamples
{
[TestMethod()]
public void FeatureRecieverOnActivationTest()
{
SampleFeatureReceiver target = new SampleFeatureReceiver();

SPSite site;
SPWeb web;
//Bind to the site where you are testing provisioning code.

site = new SPSite("http://servername");
using (site)
{
web = site.RootWeb;
using (web)
{
target.OnActivationCode(web);
}
}

Assert.IsTrue(true,
"Feature Activation did not throw any exceptions.");
}
}
}

Provisioning Workflow programatically

Scenario:
You want to provision a Workflow programatically for a given list/document library

Steps:
01. Create an SPList object that references a list or document library that hosts the items used by the workflow.
02. Create an SPList object that references an approval task list.
03. Create an SPList object that references the Workflow History list.
04. Create an SPWorkflowTemplate object by using the workflow GUID from Workflow.xml.
05. Create an SPWorkflowAssociation object that connects the SPWorkflowTemplate object with the SPList objects for the approval task list and the Workflow History list.
06. Add an SPWorkflowAssociation object to the SPList object you created in the first step.

Code:

public void ProvisionWorkflow(SPWeb web)
{
using (web)
{
//Bind to lists.
SPList approvalsList = web.Lists["Your Approval List Name Goes Here"];
SPList approvalTasksList = web.Lists["Task List"];
SPList workflowHistoryList = web.Lists["Workflow History"];

//WorkflowGUID is the workflow GUID
//from workflow.xml\<Elements>\<Workflow>\[ID].
SPWorkflowTemplate workflowTemplate =
web.WorkflowTemplates[new Guid("WorkflowGUIDWithoutBraces")];

//Create workflow association.
SPWorkflowAssociation workflowAssociation =
SPWorkflowAssociation.CreateListAssociation(workflowTemplate,
workflowTemplate.Description, approvalTasksList,
workflowHistoryList);

//Set workflow options.
workflowAssociation.AllowManual = true;
workflowAssociation.AutoStartChange = true;
workflowAssociation.AutoStartCreate = false;

//Add workflow association.
SPWorkflowAssociation workflowAssociationInList =
approvalsList.AddWorkflowAssociation(workflowAssociation);
}
return;
}

Writing , Reading and Deleting entries from property bag

Scenario:
You want to save some keys/value information for a web.

Code:

// Add new key/value pair to the property bag.
web.Properties.Add("SomeKey", "SomeValue");
web.Properties.Update();

// Read the value of some key.
string keyValue = web.Properties["SomeKey"];

// Delete the key/value pair.
web.Properties.Remove["SomeKey"];
web.Properties.Update();

Programatically making a Web Request

Scenario:
You want to read a web-page or file programatically.

Code:

private void AccessWeb(string siteURL) {
WebRequest request = WebRequest.Create(siteURL);
request.Credentials = CredentialCache.DefaultCredentials;
request.Method = "GET";

WebResponse response = request.GetResponse();
response.Close();
}
Also you can use HTTPWebRequest object

private void GetBookReview(object sender, EventArgs e)
{
StringBuilder sb = new StringBuilder();

try
{
string request = "http://xml.amazon.com/onca/xml2?" +
"t=webservices-20&dev-t=[D1LKOL21AANCMO]&"+
"AsinSearch=" + textBoxASIN.Text +
"&mode=books&type=heavy&page=1&f=xml";

HttpWebRequest req = (HttpWebRequest)WebRequest.Create(request);
HttpWebResponse resp = (HttpWebResponse)req.GetResponse();

StreamReader s = new StreamReader
(resp.GetResponseStream(),Encoding.ASCII);

XmlDocument doc = new XmlDocument();
doc.LoadXml(s.ReadToEnd());

s.Close();

sb.Append("<HR><TABLE width='95%' align='center'>");

XmlNode salesRankNode = doc.SelectSingleNode("//SalesRank");
if(salesRankNode!=null)
sb.AppendFormat("<B>Sales Rank: {0}</B><BR><BR>",salesRankNode.InnerText);

XmlNodeList customerReviewNodes = doc.SelectNodes("//CustomerReview");
if(customerReviewNodes.Count>0)
{
foreach(XmlNode reviewNode in customerReviewNodes)
{
sb.AppendFormat("<B><U>Review (Rating {0}): {1}</U></B><BR>",
reviewNode.ChildNodes[0].InnerText,
reviewNode.ChildNodes[1].InnerText);
sb.AppendFormat("<I>{0}</I><BR><BR>",
reviewNode.ChildNodes[2].InnerText);
}
}

sb.Append("</DIV>");
sb.Append("</TABLE>");
}
catch(Exception ex)
{
throw new Excepion("Sorry, unable to retrieve the books!");
}
}