We now have a working placeholder control (granted it
doesn’t do much at this point), a new template, and an events page on
our Tropical Green site. While on the events page (whose URL is http://www.tropicalgreen.net/TropicalGreen/Events.htm), click the Switch To Edit Site link in the Web Author Console, and then click Edit to switch into authoring mode for the posting. You should see the input boxes and labels that we created for our placeholder:
With the authoring
controls and a posting to view our progress created, let’s continue with
adding some functionality to our placeholder control. Regardless if the
posting is in authoring or presentation mode, we will need to retrieve
the items from the SharePoint Events list via the SharePoint List
Service Web Service. In order to access this Web Service, we need the
URL of the service, the name of the list containing the items we’re
interested in, and valid login credentials for the site.
For simplicity,
we’re going to hard-code the credentials. However, we strongly recommend
you employ a more secure solution such as encrypting the username and
password in the Web.config of the
site or allowing the content owner to enter the credentials into the
placeholder control with the URL and list name. Microsoft recommends the
data protection API (DPAPI) available in the .NET base class library.
|
Since we’ll need this functionality in both modes, we’ll create a method called GetSharePointListItems()
that requires the Web Service URL and list name while returning an
array of all items within the list. For each item returned in the array,
we want to know the following information regarding the event:
Title
Description
Location
Start Date/Time
End Date/Time
The best way to store these details is to create a new class in the TropicalGreenControlLib project. Call it SharePointEventListItem.cs and add the following code to define a business object to represent the items within a SharePoint Event list:
using System;
namespace TropicalGreenControlLib
{
public class SharePointEventListItem
{
private string _title;
private string _location;
private DateTime _startDateTime;
private DateTime _endDateTime;
// force callers to use the Factory method below
private SharePointEventListItem() {}
// Factory method used to create a new SharePointEventListItem
public static SharePointEventListItem CreateItem (string title,
string location, DateTime start, DateTime end)
{
SharePointEventListItem li = new SharePointEventListItem();
li._title = title;
li._location = location;
li._startDateTime = start;
li._endDateTime = end;
return li;
}
// title of the event
public string Title
{
get
{
return _title;
}
}
// location where the event will take place
public string Location
{
get
{
return _location;
}
}
// datetime when the event will begin
public DateTime StartDateTime
{
get
{
return _startDateTime;
}
}
// datetime when the event will end
public DateTime EndDateTime
{
get
{
return _endDateTime;
}
}
}
}
Now that we have an object that will contain each item in the list, add the GetSharePointEventListItems() method to the end of our placeholder control class, SharePointEventsPlaceholderControl.cs.
This method will use the specified URL to call a SharePoint Web Service
to retrieve a list of all the items within the specified list.
private ArrayList GetSharePointEventListItems(string sharePointUrl,
string listName)
{
ArrayList wsResultArray = new ArrayList();
// make sure URL and list name are provided
if ( (sharePointUrl == string.Empty) || (listName == string.Empty) )
return null;
// we hardcode the Web service credentials for simplicity
// You are strongly recommended to secure the login credentials
// in the same way you'd secure any other credentials such
// as a database connection string
// NOTE: You'll need to change the credentials to use an account on your
// computer that has access to the SharePoint Web services and the
// specified list.
NetworkCredential nc = new
NetworkCredential("administrator", "password", "MCMSBOOK");
// create a reference to the SharePoint List Service web service;
// assign the provided url and credentials
net.tropicalgreen.portal.Lists spWsList =
new TropicalGreenControlLib.net.tropicalgreen.portal.Lists();
sharePointUrl = sharePointUrl +"/_vti_bin/Lists.asmx";
spWsList.Url = sharePointUrl.Replace("//","/");
spWsList.Credentials = nc;
try
{
// retrieve all items returned by the Web service;
// we aren't interested in special queries, so pass null
// for all parameters except the list name
XmlNode wsXmlResults = spWsList.GetListItems
(listName, null, null, null, null, null);
// if nothing was returned by the Web service,
// return null indicating an error
if (wsXmlResults == null)
return null;
// convert XML data to business object
wsResultArray = ExtractListData(wsXmlResults);
}
catch
{
// an error occured... return null to indicate error
return null;
}
return wsResultArray;
}
Now we need the method
that extracts the list data from the XML format returned by the Web
Service and converts it to an array of our SharePointEventListItem business object. Add the following method to the placeholder control class:
private ArrayList ExtractListData(XmlNode wsXmlResults)
{
ArrayList wsResultArray = new ArrayList();
SharePointEventListItem li;
// for each result returned, extract the necessary information
// creating a new item and adding it to the result ArrayList
foreach (XmlNode resultItemNode in wsXmlResults.ChildNodes[1].ChildNodes)
{
// make sure the result item has attributes, because if not
// it's an invalid result... so skip it
if (resultItemNode.Attributes == null)
continue;
li = SharePointEventListItem.CreateItem(
resultItemNode.Attributes["ows_Title"].Value.ToString(),
resultItemNode.Attributes["ows_Location"].Value.ToString(),
Convert.ToDateTime(resultItemNode.Attributes["ows_EventDate"].Value
.ToString()),
Convert.ToDateTime(resultItemNode.Attributes["ows_EndDate"].Value
.ToString())
);
wsResultArray.Add(li);
}
return wsResultArray;
}
We need one last method
to render our SharePoint Event list items before we wire up the custom
placeholder control and preview events. Add the following method to the
placeholder control class. This method calls our GetSharePointEventListItems()
method to obtain a list of all items within the specified SharePoint
list. Once it has the contents of the SharePoint list, it renders them
for presentation using HTML:
private void DisplaySharePointEventListItems(string spWsUrl, string
spListName)
{
SharePointEventListItem li;
// make sure enough information provided in the input boxes
if ( (spWsUrl == string.Empty) || (spListName == string.Empty) )
return;
// get the SharePoint items
ArrayList items = GetSharePointEventListItems(spWsUrl, spListName);
// verify results returned
if (items == null)
litEventItemsLiteral.Text =
"<p>No events at this time. Please check back "
+ "later.</p>";
else
{
litEventItemsLiteral.Text = string.Empty;
// loop through each item in the list
foreach (object o in items)
{
// cast the object in the ArrayList as a SharePointEventListItem
li = o as SharePointEventListItem;
// if the cast was successful, show the event & increment the counter
if (li != null)
{
litEventItemsLiteral.Text += string.Format(
"<p><b>{0}</b><br>{1}<br><em>{2} - {3}</em></p>",
li.Title, li.Location,
li.StartDateTime.ToString("MMM dd, yyyy h:ss tt"),
li.EndDateTime.ToString("MMM dd, yyyy h:ss tt"));
}
}
}
}
At this point we have overridden the CreateAuthoringChildControls()
method to create our authoring controls and created all the methods
necessary to retrieve and display items from the SharePoint Event list.
The last two tasks to wrap up the authoring mode of our placeholder
control are to override the LoadPlaceholderContentForAuthoring() method, which retrieves previously saved configuration information from the XmlPlaceholder object bound to our placeholder control, and to override the SavePlaceholderContent() method, which saves the configuration information in the underlying XmlPlaceholder object.
The LoadPlaceholderContentForAuthoring() method will get the information about the configured SharePoint Event list from the bound XmlPlaceholder object, extract the SharePoint List Service Web Service URL and the name of the Event list, and call our DisplaySharePointEventListItems() method to display the content of the list:
protected override void LoadPlaceholderContentForAuthoring
(PlaceholderControlEventArgs e)
{
EnsureChildControls();
XmlDocument placeholderContents = new XmlDocument();
string sharePointUrl = string.Empty;
string spListName = string.Empty;
// load the saved config from the posting
placeholderContents.LoadXml(((XmlPlaceholder)this.BoundPlaceholder)
.XmlAsString);
// extract the necessary information
sharePointUrl = placeholderContents.DocumentElement.ChildNodes[0]
.Attributes["sharePointUrl"].Value;
spListName = placeholderContents.DocumentElement.ChildNodes[0]
.Attributes["listname"].Value;
// bind the config info to the text boxes
txbSharePointUrl.Text = sharePointUrl;
txbListName.Text = spListName;
// show the items
DisplaySharePointEventListItems(sharePointUrl, spListName);
}
The SavePlaceholderContent() method will create a small XML string containing the Web Service URL and list name and insert it into the bound placeholder:
protected override void SavePlaceholderContent(PlaceholderControlSaveEventArgs e)
{
string config = string.Empty;
// make sure enough information is provided in the input boxes
if ( (txbSharePointUrl.Text == string.Empty)
|| (txbListName.Text == string.Empty) )
return;
// save the config information
config = string.Format("<config><sharepointlist sharePointUrl=\"{0}\""
+ "listname=\"{1}\" /></config>",
txbSharePointUrl.Text, txbListName.Text);
((XmlPlaceholder)this.BoundPlaceholder).XmlAsString = config;
}
Let’s see how our control looks in authoring mode. Build the TropicalGreenControlLib project, open a browser, and navigate to http://www.tropicalgreen.net/TropicalGreen/Events.htm. If you hadn’t logged in already, go ahead and do so. Once you’re logged in, click the Switch To Edit Site link in the Web Author Console, and then click Edit to switch into authoring mode for the posting. Enter the following into the two input boxes and click Save and Exit in the Web Author Console:
Now all we need is to wire
up the two additional methods to create and populate the presentation
controls for our placeholder control using CreatePresentationChildControls(), get the information about the configured SharePoint Event list from the bound placeholder, and call DisplaySharePointEventListItems() to display the items using the method called LoadPlaceholderContentForPresentation():
protected override void CreatePresentationChildControls
(BaseModeContainer presentationContainer)
{
litEventItemsLiteral = new LiteralControl();
presentationContainer.Controls.Add(litEventItemsLiteral);
}
protected override void LoadPlaceholderContentForPresentation
(PlaceholderControlEventArgs e)
{
EnsureChildControls();
XmlDocument placeholderContents = new XmlDocument();
string sharePointUrl = string.Empty;
string spListName = string.Empty;
// load the saved config from the posting
placeholderContents.LoadXml(((XmlPlaceholder)this.BoundPlaceholder)
.XmlAsString);
// extract the necessary information
sharePointUrl = placeholderContents.DocumentElement.ChildNodes[0]
.Attributes["sharePointUrl"].Value;
spListName = placeholderContents.DocumentElement.ChildNodes[0]
.Attributes["listname"].Value;
// show the items
DisplaySharePointEventListItems(sharePointUrl, spListName);
}
That should do it... build the TropicalGreenControlLib project one last time and navigate back to the Events page at http://www.tropicalgreen.net/TropicalGreen/Events.htm.
We now have a
placeholder control that will extract items from a SharePoint Events
list using the SharePoint List Service Web Service. Where could we go
from here? This control could be taken to the next level by creating a
friendlier input dialog where the content author would enter the URL of
the SharePoint portal or site and the placeholder control would return a
list of child sites to choose from, as well as a selection of all the
SharePoint lists available in each site. Instead of being coded towards
the Events list, we could modify the GetSharePointEventListItems() and DisplaySharePointEventListItems() to retrieve and display any type of SharePoint list.
But why stop there? We could adopt the MCMS Page Listing Web Part model in creating custom views by passing the entire ArrayList
(maybe creating a more intelligent strongly typed collection) to an
assembly to provide complete control over the rendering of the
presentation. If your MCMS site also supports Windows Authentication, or
if your SharePoint portal is configured for anonymous access, you could
determine if the current user has access to the specified list and if
so, create a hyperlink straight into the SharePoint item detail page. We
could also take the raw XML result returned by the Web Service and run
it through an XSLT for a more dynamic rendering of the content (such as
implementing paging).
Your business needs
and requirements may affect the design and implementation of your own
placeholder that pulls information from a SharePoint list. In our
example, the placeholder pulls the information from the SharePoint list
every time the placeholder is displayed in both authoring and
presentation mode. This may not be a performance-friendly method to
render the list contents in the placeholder as Web Services incur their
own overhead. In addition, if your company has strict auditing
requirements where you need to produce a copy of the posting from a
given time, the solution as we designed wouldn’t suffice, as the content
is pulled on demand from the SharePoint list and the contents of the
list being displayed are not stored in the placeholder.
These are just some of the
additional issues you’d need to consider when designing and developing
your own implementation. The hard part of pulling content from a
SharePoint List Service Web Service has been demonstrated in this brief
placeholder control. You can use your imagination in customizing this
placeholder control for your specific needs.