PostRank Topblogs 2009 - #20 in Sharepoint

Windows Live Alerts web tracker
Chat with me if I'm online!
search blog
most popular
MCP MCTS MCT MVP

SP 2010: SharePoint Server 2010 - Creating a custom Document ID provider

Author: Tobias Zimmergren
http://www.zimmergren.net | http://www.tozit.com | @zimmergren

Introduction

In this article I will talk about how you can create your custom Document ID provider for your SharePoint Server 2010 installation. Sometimes I've been getting the question weather or not it's possible to change the behavior or change the way the Document ID's are generated, and some people have a tendency to say no to that question, just because there's no interface or out of the box functionality to do so.

I'll give you a quick walkthrough of how you can extend your Site Collection by adding a custom Document ID provider, that will automatically generate custom ID's based  on your own algorithms entirely!

Recommended reading about Document ID's before proceeding: 
http://msdn.microsoft.com/en-us/library/ee559302(office.14).aspx

Document ID overview

This section will give you a very brief conceptual overview of Document ID's in SharePoint Server 2010.

What is Document ID's?

Document ID's in SharePoint Server 2010 provide you with the ability to tag documents with a unique identification number. Something a lot of my clients have done manually or by implementing custom solutions to take care of in SharePoint 2007. With this new feature, you get all the required functionality to tag documents with unique identification numbers based on a specific pre-set formula with a custom prefix.

See this sample screenshot for an example:
image

Where do I enable Document ID's for my Site Collection?

In order to enable Document ID's in your Site Collection, you'll need to activate the Site Collection Feature called Document ID Service.

See this screenshot for an example:
image

How do I change the way my Document ID's are generated?

If you want to alter the way the Document ID's are generated for your documents in your Site Collection, you can do that by navigating to:

Site Actions - Site Settings - Document ID Settings, like so:
image

From this new settings page, you'll get the possibility to tell SharePoint how it should generate your unique ID's. You can specify a prefix for all the generated ID's:
image

I want to take it one step further!

If you're not quite satisfied with the way SharePoint 2010 generates your Document ID's for you, then you should most definitely follow along with the rest of this article as I will guide you through the steps to create your very own Document ID provider to generate exactly the kind of ID's you want - based on your very own code/algorithms!

Bring it on!

Learning about a SharePoint 2010 Custom Document ID provider

This section will give you an overview of what you will need in order to create a custom Document ID provider for SharePoint Server 2010!

Note: As of this writing MSDN isn't fully updated on these new SharePoint Server namespaces. Some details may or may not change when SharePoint Server 2010 is released into the wild (RTM)

Microsoft.Office.DocumentManagement

The namespace Microsoft.Office.DocumentManagement contains a class called DocumentIdProvider, which will be the base for our upcoming project!

Microsoft.Office.DocumentManagement.DocumentIdProvider

This is the class we will derive from when creating our custom provider. It contains three (3) abstract methods and one (1) abstract method that we need to implement:

A description of each of these methods and the property will be made inline in my code in the samples!

Creating a SharePoint Server 2010 Custom Document ID provider

Let's code this little piece of functionality, shall we. The final project (very basic) will look something like this:
image

So, let's get coding.

1. Create a class and derive from DocumentIdProvider

public class CustomDocumentIdProvider :
Microsoft.Office.DocumentManagement.DocumentIdProvider
    {
        // Method to generate the actual document ID. Awesomeness lives here!
        public override string GenerateDocumentId(SPListItem listItem)
        {
            // In this method we will tell SharePoint how it should generate
            // the unique ID we want.
            // In my case, I've just created a dummy-generator. 
            // Normally you would perhaps want to fetch this from another system or
            // generate it properly instead of like this.. 

            // Points to a method I've created that generates foo-ID's
            return FooSampleIDGenerator.GetFooUniqueID();
        } 

        public override bool DoCustomSearchBeforeDefaultSearch
        {
            // If set to true: It will call the GetDocumentUrlsById method before search
            // If set to false: It will use SharePoint Search before custom methods
            get { return false; }
        } 

        public override string[] GetDocumentUrlsById(SPSite site, string documentId)
        {
            // Returns an array of URLs pointing to 
            // documents with a specified DocumentId
            // An empty string array 

            // This is where you will implement your logic to find
            // documents based on a documentId if you don't want to use
            // the search-approach.
            return new string[] { };
        } 

        public override string GetSampleDocumentIdText(SPSite site)
        {
            // Returns the default Document ID value that will be initially
            // displayed in the Document ID search web part as a help when searching
            // for documents based on ID's.
            // This should correspond with the way you've designed your ID pattern
            return "AWESOME-12345-67890-SharePointRules";
        }
    }

2. Create a Feature Receiver to hook up your custom provider with your Site Collection

public class ProvisionCustomDocIdProviderEventReceiver : SPFeatureReceiver
{
    public override void FeatureActivated(SPFeatureReceiverProperties properties)
    {
        DocumentId.SetProvider(properties.Feature.Parent as SPSite,
                                                                 new CustomDocumentIdProvider());
    }
    public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
    {
        DocumentId.SetDefaultProvider(properties.Feature.Parent as SPSite);
    }
}

Actually, you're all done with the code for now.

3. Go to Document ID Settings page and see this message appear

image

This basically means that your custom provider has been successfully enabled (as per our Feature Receiver).

4. See that the Document ID's on your documents now is using your custom provider

(Please allow for some time to pass so the Timer Jobs can do their magic, or manually go into Central Admin and run the timer jobs instantaneously)

Behold, awesome custom Document ID provider in action:
image 

Summary and Download

What did we just do?

What we just did was to create a custom Document ID provider that generates our very own custom Document ID's based on whatever algorithm or pattern we want. There's no need to follow the built-in format for your generated IDs - which some people have presented in their seminars and blogs. So there you go, step by step!

This could be especially awesome if you've got an external system generating Document ID's already, and you want SharePoint to use those ID's alongside whatever other system is running. Use your own imagination as to what can be done. The code is in your hands, Obi Wan Coder!

Download project

You can download my sample project here

Enjoy, and please don't be afraid to leave comments!


Published: Apr-13-10 | 36 Comments | 0 Links to this post

MOSS 2007: Creating a custom AJAX UserControl that will query the SharePoint Search Query Object Model to perform searches

Author: Tobias Zimmergren
Url:
http://www.zimmergren.net

If you've read my last two blogposts you already know how to configure ASP.NET 2.0 AJAX for your SharePoint Server and how do deploy a UserControl that uses AJAX functionality on you SharePoint Server.

You can find my previous articles here:

This blogpost shows a simple implementation of a UserControl that uses the Object Model to query the search service using a keyword and then using an UpdatePanel in AJAX to present the result to the user without any page reloads.

Let's create an AJAX based UserControl which purpose will be to search using the Search Query Object Model

Copy the nessecary assemblies to your local bin folder (I'm deploying locally to the WebApplication on port 80)

To make this work (in this case, since I'm deploying to the UserControls folder with inline code, not calling any own assemblies) you need to copy the two .dll files to your /bin folder of the WebApplication where you want to deploy this UserControl.

  1. Copy C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\ISAPI\Microsoft.Office.Server.dll
  2. Copy C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\ISAPI\Microsoft.Office.Server.Search.dll
  3. Paste the two files to C:\Inetpub\wwwroot\wss\VirtualDirectories\80\bin\ (Note: It can be any other port other than 80 if you're deploying to another WebApplication)

The reason that we copy these files to our deployment target's /bin is simply that I'm deploying locally to that WebApplication and some of the namespaces and classes that we need to use in order to be able to query the Search Object Model are availible in those assemblies. There's better ways to accomplish this, but to keep it simple I'm going with this approach.

Create the custom AJAX UserControl that will query the SharePoint Search Query Object Model

For simplicity, I'll reference all the servercode inside the <script> block and not using a code-behind assembly.

  1. Launch Visual Studio 2005 (or whatever version you're running)
  2. Create a new file based on the "Web User Control" template, name it as you please
  3. Add the following tags just below the Control directive:

    <%@ Register Assembly="System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" Namespace="System.Web.UI" TagPrefix="asp" %>
    <%@ Import Namespace="Microsoft.Office.Server" %>
    <%@ Import Namespace="Microsoft.Office.Server.Search.Query" %>
    <%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="ajaxToolkit" %>


    It could look something like this:
     searchajax1
  4. Just below all the references you just added, add the following code:

    <script runat="server">

    </script>


  5. Add the following code right below the references you just added. This code is simply to give us a simple user interface for the user to perform the search from:

    <asp:UpdateProgress ID="UpdateProgress1" runat="server" AssociatedUpdatePanelID="UpdatePanel1">
        <ProgressTemplate>
            <img src="http://zimmergren/hostedImages/ajax-loader.gif" alt="Searching..." style="border: 0px none #fff;"/>
        </ProgressTemplate>
    </asp:UpdateProgress>
    <asp:UpdatePanel ID="UpdatePanel1" runat="server">
        <ContentTemplate>
            Enter a keyword to search for<br />
            <asp:TextBox ID="tbSearchString" runat="server" Width="230px"/><br />
            <asp:Button ID="btnSearch" runat="server" Text="Search" OnClick="btnSearch_Click" />
            <asp:Literal ID="literalSearchResults" runat="server" />
        </ContentTemplate>
    </asp:UpdatePanel>


    It could look something like this:
     searchajax2

  6. Insert this code inside the <script>-tag you created earlier:

    protected void btnSearch_Click(object sender, EventArgs e)
    {
        // Job insurance, to pause and show that the UpdateProgress works
        System.Threading.Thread.Sleep(2000);
        try
        {
            string startTable = "<table style=\"width: 100%;\">";
            string endTable = "</table>";
            string searchResultItem =
            "<tr>" +
                "<td><a href=\"{0}\">{1}</a></td>" +
            "</tr>" +
            "<tr>" +
                "<td>" +
                    "<em>{2}</em>" +
                "</td>" +
            "</tr>" +
            "<tr>" +
                "<td>Site: {3}</td>" +
            "</tr>" +
            "<tr>" +
                "<td style=\"padding-bottom: 10px;\">Author: {4}, Item Size: {5}</td>" +
            "</tr>";

            string outputResults = startTable;

            ServerContext context = ServerContext.GetContext("SharedServices1");
            KeywordQuery keywordQuery = new KeywordQuery(context);

            keywordQuery.ResultTypes = ResultType.RelevantResults;
            keywordQuery.EnableStemming = true;
            keywordQuery.TrimDuplicates = true;
            keywordQuery.QueryText = tbSearchString.Text;

            ResultTableCollection results = keywordQuery.Execute();
            ResultTable resultTable = results[ResultType.RelevantResults];

            if (resultTable.RowCount == 0)
            {
                literalSearchResults.Text = "Sorry, your search didn't return any results";
            }
            else
            {
                while (resultTable.Read())
                {
                    outputResults += string.Format(searchResultItem,
                        resultTable.GetString(5),
                        resultTable.GetString(2),
                        resultTable.GetString(6),
                        resultTable.GetString(8),
                        resultTable.GetString(3),
                        resultTable.GetString(4));
                }
            }
            outputResults += endTable;
            literalSearchResults.Text = outputResults;
        }
        catch (Exception ex)
        {
            literalSearchResults.Text = ex.Message;
        }
    }

    Instead of going all crazy about how the code actually works with the Search Query Object Model, I'm just pasting the code here for you to try and will explain the Search Query Object Model in another article.

Deploy the UserControl
  • Copy or Save the UserControl to the following location: C:\Inetpub\wwwroot\wss\VirtualDirectories\80\UserControls\ and you're all set.

If you've configured AJAX and installed the SmartPart you should be all set and be able to use it. See this short post on using the SmartPart if you don't know already.

Final Result

This is what it looks like when you hit the button (the red image spins around for 2 seconds (see the code, Thread.Sleep(2000)) to show how it will look if it's a heavy query and needs some loading time.
 searchajax3

This is what the result will look like, note that everything is done within an UpdatePanel and we do not experience the page to reload, or any visual postbacks.
 searchajax4

Download the UserControl here


Published: Mar-13-08 | 6 Comments | 0 Links to this post

SharePoint Cross List Queries in a custom UserControl

Author: Tobias Zimmergren
Url:
http://www.zimmergren.net

I got the question last week weather it's possible to get items from all lists of <your chosen type here> gathered and displayed on one page.
This is - like most things - possible in SharePoint without any greater efforts. With something called Queries we can use the object model to query SharePoint and get a result quite painlessly.

To demonstrate a very simple example, I've created a very small usercontrol (for use with Jan Tielen's SmartPart) that looks like this:

 crossqueries1

This code will combine all the items in all of the TaskLists on the current SiteCollection and display them in a simple GridView as seen above in the screenshot.

Code for the Cross List Query UserControl

 crossqueries2

 crossqueries3

Simple enough, huh?
Of course you can create webparts, usercontrols, application pages, or any other type of application to interact with the object model in this way. I chose to do it using a UserControl for the ease of deployment, testing, development and demonstration.

For your conveniance I've uploaded the UserControl (.zip) here so you can download it.


Published: Mar-09-08 | 2 Comments | 0 Links to this post

MOSS 2007: Customizing the Search Results Page (XSLT) - Part 2 - Add highlighting

Author: Tobias Zimmergren
Url:
http://www.zimmergren.net

In one of my previous blogposts I wrote about how you easily could alter the XSLT of a the Search Core Results Web Part on your Search Results Page in order to achieve a customization to the presentation of the output.

In this article I will scratch on the surface of some more XSLT and show you how you can implement the HitHighligting Template in order to achieve colored/customized display of the search words you entered.

What is the HitHighligting Template?

Well, basically the HitHighligting template offers you the ability to highlight words that are used in your search. It offers you the possibility to highlight words in the following three result sections: Title, Url and Description (And that's basically all you need, mostly)

 searchresultstwo1

Study the following XSLT, as per MSDN:

<hithighlightedsummary>
  <c0>SharePoint</c0> <c1>namespace</c1> provides types and members that can be used for working with a <c0>SharePoint</c0> site  <ddd /> a top-level <c2>class</c2> that represents a <c0>SharePoint</c0> site and provides access to its collection of subsites <ddd /> <c0>SharePoint</c0> <c1>namespace</c1> and a brief description of each.
</hithighlightedsummary>
<hithighlightedproperties>
  <HHTitle>Microsoft.<c0>SharePoint</c0> <c1>Namespace</c1></HHTitle>
  <HHUrl>
http://msdn.microsoft.com/library/default.asp?url=/library/en-     us/spptsdk/html/tsnsMicrosoft<c0>SharePoint</c0>_SV01017995.asp</HHUrl>
</hithighlightedproperties>

You may notice that the sections hithighlightedsummary, HHtitle and HHUrl elements contain childs (<c0>,<c1> etc). This basically means that for each instance of the words entered in your search, you get a set of highlight-tags that encloses that word. This is the default behaviour of the SharePoint Search. First word gets <c0>, second word gets <c1> and so on...

How do I add the Highlighting functionality?

Note: If you do not know how to access the XSLT of the Search Core Results Web Part, view my previous post on the subject.

In order to customize the presentation of the search result and make your words highlighted, you basically only need to add some tags to the XSL-template for each search word you want to highlight as you can see in the screenshot below.

Now locate the following section in your Search Core Results Web Part (It already exist):

<xsl:template name="Hithightlighting">

And since this template exists from the beginning, all you really have to do is to customize the style attribute and add a color property of the <b> tag (I replaced it with a <strong> tag instead, for sake of standards)
Then you can simply specify the styles for each highlighted word as picted in the following screenshot:

 searchresultstwo2

It's simple as that. I hope this helped some of you to get started on some basic Search Core Results XSLT customizations.


Published: Sep-01-07 | 3 Comments | 0 Links to this post