Book Image

Microsoft SharePoint 2010 Business Application Blueprints

Book Image

Microsoft SharePoint 2010 Business Application Blueprints

Overview of this book

SharePoint is an incredibly powerful platform that can support a wide variety of business scenarios. In many cases it needs to be configured or extended in order to deliver fully featured business solutions. While some books merely talk about the capabilities of SharePoint in general and leave you to figure out how they apply to your situation, this book takes a different approach. Each chapter provides easy-to-understand, step-by-step instructions along with screenshots to help build exciting SharePoint business solutions that extend the platform. By the end of this book the reader will be a SharePoint developer to be reckoned with. This book will dive into a diverse set of real-world scenarios to deliver sample business solutions that can serve as the foundation for your own solutions. This book draws from the author's extensive experience with SharePoint to leverage the platforms underlying services to provide solutions that can support Social Collaboration, Content and Document Management, as well as project collaboration. Each chapter represents a new business solution that builds on the overall platform to deliver more complex solutions and more advanced techniques. By the end of the book the reader will understand how to leverage the SharePoint platform to build their own business solutions.
Table of Contents (15 chapters)
Microsoft SharePoint 2010 Business Application Blueprints
Credits
About the Author
About the Reviewers
www.PacktPub.com
Preface

Building an Employee Corner Web Part


Highlighting employees is a great way to increase collaboration and user engagement. In the past this was done in employee newsletters or other communication methods, but as those methods go electronic and the focus moves towards the Intranet portal as the central communication hub, it becomes another type of information that should be included.

Note

SharePoint Server's user profiles can provide a rich set of details about users, and can be leveraged to provide a great source of dynamic content around important dates, organization structure, interests, clients, and past projects.

The Employee Corner Web Part will present a list of new employees based on the Hire Date field in the user profiles. Additional examples could include employee of the month (or quarter), birth dates, or employee anniversaries.

Approach

To create the Employee Corner Web Part we will create a custom Web Part in Visual Studio 2010. The Web Part will leverage the Search API's FullTextSqlQuery class to query the People search scope bringing back values stored within the user profiles that are currently indexed.

It is important to understand the underlying architecture in order to know which development path is really an option. Normal SharePoint list and library data is stored inside of the content database associated with the site collection. The content associated with SharePoint's service applications are however stored in separate databases since those services and the content is not tied to any one site, but available globally to all web applications associated with the service application. This means that the service applications are not accessible via the Client OM or via Sandbox Solutions without implementing some sort of Full Trust proxy that would have to be installed on the server and provide access to the server API. Based on these boundaries, a server solution makes the best choice for the approach in most environments. If the solution needs to be deployed to an environment with server deployment limitations the Full Trust proxy or other alternatives would have to be evaluated.

Creating the Web Part

To create the initial project:

  1. 1. Open Visual Studio 2010.

  2. 2. Select File, then New Project.

  3. 3. Browse the Installed Templates and select Visual C# | SharePoint 2010, and then Empty SharePoint Project as shown in the following screenshot:

  4. 4. Enter the project details such as Name, Location, and Solution name.

  5. 5. Within the SharePoint Customization Wizard, provide a path to your SharePoint site and then be sure to select the option to Deploy as a farm solution as shown in the following screenshot:

  6. 6. Right-click on the project file and select Add New Item.

  7. 7. From the template selection screen select the Web Part option.

  8. 8. Provide the name EmployeeCorner and click the Add button as illustrated in the following screenshot:

  9. 9. Rename the Feature1 item SPBlueprints.WebParts.

  10. 10. Select the SPBlueprints.WebParts feature item and provide a Title and Description. It should resemble the following screenshot:

  11. 11. Edit the definition of the EmployeeCorner.webpart file so that the Web Part definition added to the Gallery is meaningful as displayed in the following EmployeeCorner.webpart definition:

    <?xml version="1.0" encoding="utf-8"?>
    <webParts>
    <webPart xmlns="http://schemas.microsoft.com/WebPart/v3">
    <metaData>
    <type
    name="SPBlueprints.WebParts.EmployeeCorner.EmployeeCorner,
    $SharePoint.Project.AssemblyFullName$" />
    <importErrorMessage>$Resources:core,ImportErrorMessage;</import
    ErrorMessage>
    </metaData>
    <data>
    <properties>
    <property name="Title" type="string">Employee
    Corner</property>
    <property name="Description" type="string">SPBlueprints
    - The Employee Corner WebPart displays all new employees that
    started in the last 30 days.</property>
    <property name="SearchProxyName" type="string">Search
    Service Application</property>
    </properties>
    </data>
    </webPart>
    </webParts>
    
  12. 12. The completed project structure should resemble the following screenshot:

Defining a Web Part property

When creating a Web Part, there is often some configuration data that is needed to be able to reuse the Web Part for different sites or purposes. Creating a Web Part property makes it much easier to maintain the code than embedding configuration values in the code.

For the EmployeeCorner Web Part, we are going to establish a text field that allows the user to specify the Search service application to use when searching for the user profiles in the next section. The SearchProxyName property is detailed as follows:

private string searchProxyName;
[WebBrowsable(true),
WebDisplayName("Search Proxy Name"),
WebDescription("Please provide the name of your Search Service
Application."),
Personalizable(PersonalizationScope.Shared)]
public string SearchProxyName
{
get { return searchProxyName; }
set { searchProxyName = value; }
}

Connecting to the Search service application

To work with the Search service application we need to start by adding a reference to the following namespaces within the project and EmployeeCorner Web Part:

Microsoft.SharePoint.Administration
Microsoft.Office.Server.Search
Microsoft.Office.Server.Search.Query
Microsoft.Office.Server.Search.Administration

The connection to the service application is established through the SearchServiceApplicationProxy object, which is loaded using the SearchProxyName Web Part property previously identified. The following code should be added to a new method called Display() that is called from the OnLoad() method:

SearchQueryAndSiteSettingsServiceProxy settingsProxy =
SPFarm.Local.ServiceProxies.GetValue<SearchQueryAndSiteSettingsSer
viceProxy>();
SearchServiceApplicationProxy searchProxy =
settingsProxy.ApplicationProxies.GetValue<SearchServiceApplication
Proxy>(this.searchProxyName);
FullTextSqlQuery mQuery = new FullTextSqlQuery(searchProxy);

The FullTextSqlQuery class provides an interface to execute complex queries against the search index. Queries executed against the index will perform faster than queries against the actual content such as a list or a library. As the amount of content increases, and as the number content sources you search across increases, the performance gains are even more significant, since the index provides a pre-processed source for the information.

For the FullTextSqlQuery, we will define the fields that we want to see, the scope, and the criteria to match it. For the fields you will want to make sure that the desired fields are set up as Managed Properties. The name of a Managed Property may be different than the name in the actual profile. In this example, the user profile field's internal name is SPS-HireDate, but the Managed Property name is simply HireDate. You can check the Managed Property mappings within the Search service application by clicking the Metadata Properties link in the Quick Launch menu.

For any search involving people, it is required that you use the People search scope so that it returns user profile information instead of regular site content. The New Hire Query will pull the specified fields, from the People search scope, for anyone with a HireDate that is within 30 days of today. An example of the query is shown as follows:

mQuery.QueryText = "SELECT LastName, FirstName, JobTitle,
accountname, HireDate, Birthday, PictureThumbnailURL FROM SCOPE()
WHERE (\"scope\" = 'People') AND HireDate >= DATEADD (DAY, -30,
GETGMTDATE())";

After setting the query, there are a few other properties that need to be set before executing the query, which are shown as follows:

mQuery.ResultTypes = ResultType.RelevantResults;
mQuery.TrimDuplicates = true;
mQuery.RowLimit = 100;
ResultTableCollection resultNew = mQuery.Execute();

Formatting the Web Part

Formatting the output of the Web Part begins with identifying any controls that are needed within the CreateChildControls() method. This method will run as part of the initialization process before the OnLoad() method, ensuring the controls are available. The output that will be rendered, will be added to the literal control. The CreateChildControls() method code is shown as follows:

protected override void CreateChildControls()
{
this.literalMessage = new Literal();
this.literalMessage.ID = "literalMessage";
this.Controls.Add(this.literalMessage);
}

Within the Display() method, after the Execute() method previously called, we will now process the results. When executing a search query, the resulting ResultsTableCollection contains a number of different types of results. For the content that will be displayed here, we are interested in the ResultType.RelevantResults. We will check to validate that there are records returned, then extract just the relevant results.

Content that will be rendered to the screen will be formatted in a StringBuilder object called messages. After the main content is structured, we will iterate through the DataTable object to add each of the individual records returned from the query. The code is shown as follows:

DataTable resultsNewHire = new DataTable();
if (resultNew.Count > 0)
{
ResultTable relevantResults =
resultNew[ResultType.RelevantResults];
resultsNewHire.Load(relevantResults,
LoadOption.OverwriteChanges);
messages.AppendFormat(@"<table width='360' border='0'
cellpadding='0' cellspacing='0'><tr><td align='left'
valign='top' width='14' class='ms-wpTdSpace'
background='/Style%20Library/Images/shadow-
left.png'>&nbsp;</td><td
background='/Style%20Library/Images/mid-
background.jpg'><table><tr><td colspan='2' class='ms-
standardheader ms-WPTitle'><b>{0} New Employees in the last 30
days!</b></td></tr>", resultsNewHire.Rows.Count);
foreach (DataRow row in resultsNewHire.Rows)
{
messages.AppendFormat(@"<tr valign='center'><td width='100'><a
href='/my/person.aspx?Accountname={3}'><img src='{5}' alt='{1}
{0}' border='0'></a></td><td width='250' align='left'
valign='top'><a href='/my/person.aspx?Accountname={3}'>{1}
{0}</a><br>{2}<br>{4}</a></td></tr>", row[0].ToString(),
row[1].ToString(), row[2].ToString(), row[3].ToString(),
String.Format("{0:dddd, MMMM d yyyy}", row[4]),
row[6].ToString());
}
messages.AppendFormat(@"</table></td><td align='right'
valign='top' width='14' class='ms-wpTdSpace'
background='http://intranet/Style%20Library/Images/shadow-
right.png'>&nbsp;</td></tr></table>");
}

Employee Corner Web Part displayed

The rendered version of the Employee Corner Web Part is shown in the following screenshot: