07 Juli 2008

Language filter with Faceted Search

SharePoint Search extracts the language of a document during the crawl and use this information for the calculation of the relevancy while generating search results.

This behavior cause problems in multilingual enterprises. SharePoint search returns mainly documents in the user language (respectively the browser language).

Based on a post from Patrick Tisseghem about a hidden managed property which contains the language of a document. This managed property is called "DetectedLanguage". As Patrick mentioned, the language is stored as an integer value (9 = English, 7 = German, etc.). It could be used on your SharePoint out of the box (give it a try and search for "somekeyword deletectedlanguage:9").

But the real power of this managed property is developed in conjunction with Faceted Search. This open source SharePoint extensions allows you to use SharePoint meta data (or Managed Properties) as facets to refine your search. Go to the CodePlex project page and have a look at there web casts for more information.

You can extend Faceted Search to use your own managed properies as facets. In this way, you also can use the "detectedlanguage" property. Just paste to following XML snipped in the property "Select columns for Facets" in the "Search Facets" Web Part. With this, you will be able to restrict your search results based on the lanuage of a document.

As a side effect, you will see, that SharePoint (or the underlining IFilter) does lots of errors while detecting the language of a document.

Here is the XML snipped for the Faceted Search Web Part configuration:

23 Juni 2008

Update Content Type with a Feature

If you deploy your Content Types with a Feature, you will run into a problem, when you would like to modify the Content Type. If you modify and redeploy the Feature, then the Site Content Type is disconnected from the List Content Type. This is because very time a Content Type is assigned to a list, a new List Content Type is created, which inherits from the Site Content Type.

If you do the modification manually you should always modify the Site Content Type. While doing via Site Settings, you have an option which force SharePoint to propagate the modification to all the List Content Types inherited from the Site Content Type.

But when you do the modification by changing the Feature, then SharePoint won't update the inherited List Content Types. There are some STSADM extensions which do this work for you (i.e. from Gary Lapointe or Søren Nielsen).

I took the Code from Søren Nielsen and put it in a FeatureActivated Event Handler. In my Content Type Feature.xml I set the ReceiverAssembly and ReceiverClass attribute. This allows you the modify the Content Type in the Feature, upgrade the WSP, deactive and finally reactive the Feature. Reactivating the Feature will change the Site Content Type. SharePoint will propagate the modification with the FeatureActivated Event Handler to all the List Content Types inherited from the Site Content Type.

If you just add some Site Columns to your Site Content Type (or delete some unused Columns), this would make your deployment and change management process much more easier. Perhaps almost as easy as the good old ALTER TABLE SQL scripts ;)

Here is the my Code. Just copy the ProcessWeb() and all the other method from Søren Nielsen's blog.

03 Juni 2008

Object Required Error – Drag & Drop of Web Parts

Some days ago one of my MOSS 2007 WCM sites faced up with an "Object Required" Java Script error while a content editor tried to drag & drop a Web Part in a custom Web Part Zone. Usually this sets the index of the Web Part in this Zone.

All right.. I tried to debug the problem with Visual Studio. The Debugger gave me the information about a missing offset in function “MSOLayout_GetRealOffset”, but I wasn't able to figure out what the reason for this behavior could be. After the provisioning of a new Site with the Standard Master Pages and Style Sheets applied, the error didn’t appear anymore. This means that it had something to do with my custom Styles I applied.

Step by step I reapplied my CSS and discovered that the error only appears when I apply the custom styles for my WebPart Zone Holder Divs.

In my CSS I had defined the property: “position: relative”, which caused the error.



You should use no other position definitions than “position: static”. This is the only way it works.



Drag & Drop anyway just works in Internet Explorer, but to miss this functionality is indeed not user friendly.

30 Mai 2008

Display Profile Properties in Table Style

I would like to show you, how you can display profile properties in a table. For example this would allow you to generate a telephone directory from your profile data.

Briefly this would be done in two steps: indexing your profile properties and displaying them with a People Results Web Part.

Let's start creating a managed property. Every property you would like to display on the list, must be crawled by the index and mapped to a managed property.

Creating a managed property
  1. On the SSP admin site, go to the "User profile and property" page, select "View Profile Properties" and select the profile property, you want to display. You could also create new properties.
  2. Make sure that the checkbox "Indexed" is selected.
  3. Repeat this set for every property.
  4. Do a full crawl of the SSP/MySite content source (usually the "Local Office SharePoint Server sites")... and wait until it is completed.
  5. Now you can create managed properties. For this, go to "Search Settings" and choose "Metadata property mappings".
  6. First check, if your desired property is no all ready managed. If not, create a new managed property and add a mapping to the crawled property.
  7. Again start a full crawl.

Sample with the managed property "Xing" which is mapped to the crawled propery "Xing".

Bringing the properties to the screen

Of course you could write a Web Part which iterates over the profiles and then render the data in a gridview. But you can also do this by configuration with the People Search Core Results Web Part.
  1. To begin, you have to create a new Web Part Page and add the "People Search Core Result s".
  2. In the Web Part Properties you set a "Fixed Keyword Query" and select a Cross-Web Part Query ID different from "user query". As "Fixed Keyword Query" you could enter contentclass:"SPSPeople" to display all profiles. But you can also define a custom query, which matches only to a parts of the profiles in your Shared Service Provider.



  3. Under "Selected Columns" add a line for every Managed Property. Check first, if it's not allready there. In our sample, I added <column name="Skills"> before the closing </columns> tag.
  4. Now we have to edit the XSL. If you are a native XSL speaker like my fellow worker Dänu, you can start creating your XSL and can stop reading here.



  5. If not, here some tricks how this could be done. I would suggest, that you copy the existing XSL. This XSL could be used later as a starting point.
  6. With the following XSL you can output the XML code of the search resutls.

    <?xml version="1.0" encoding="utf-8"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="@* | node()">
    <xsl:copy>
    <xsl:apply-templates select="@*|node()" />
    </xsl:copy>
    </xsl:template>
    </xsl:stylesheet>

    Copy & Paste it in to the XSL editor field and hit "Apply".
  7. Now you have to look at the HTML source code. Search for and copy the hole tag (until the closing ) to the clipboard. In this XML you will see all the properties returned by SharePoint.
  8. If you are familiar with Visual Studio 2008 you could use it to generate a new XSL. Save the XML output to a file und try to run the XSL against that file (Menu: XML \ Show XSLT Output).

Here is a sample XSL which display the name, the e-mail and a like to a Xing profile.


<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<!-- XSL transformation starts here -->
<xsl:template match="/">
<table>
<tr>
<td>Name</td>
<td>Email</td>
<td>Xing</td>
</tr>
<xsl:apply-templates />
</table>
</xsl:template>

<!-- This template is called for each result -->
<xsl:template match="All_Results/Result">
<xsl:variable name="id" select="id"/>
<xsl:variable name="url" select="url"/>
<tr>
<td>
<a href="{$url}" id="{concat('CSR_',$id)}">
<xsl:value-of select="preferredname"/>
</a>
</td>
<td>
<xsl:value-of select="workemail"/>
</td>
<td>
<xsl:if test='string-length(xing) &gt; 0'>
<a href="{xing}" id="{concat('XING_',$id)}">
<xsl:value-of select="xing"/>
</a>
</xsl:if>
</td>
</tr>
</xsl:template>
</xsl:stylesheet>

28 März 2008

WCM Approval Configrator

Today I wrote a small application which will allow you to set some of the approval workflow settings on a per-site base. This apps will modifiy the workflow association for you on every "Pages" library in the selected sites.

You have the possibility to enable or disable the approval workflow, choose the participants of the workflow and allow or disallow to change the participants lists on workflow start.

I created this application to configure the approval workflow on a customer site. If you want you can download and extend the source code. You will see, that the association data is stored in a XML and with a little debugging you will be able to also modify the other parameters.

Here you can download the application including source code and Visual Studio 2008 project.

Update 10/17/2008: I moved the code to an ASPX, packed as WSP and uploaded to CodePlex. You can find the download on the MOSSApprovalConfig project site.

24 März 2008

how to: avoid loading “name.dll” active X component in anonymous WCM scenarios

just imagine.. after hard weeks of SharePoint development you configure your anonymous authentication provider to publish your web app anonymously to the internet. After you first browse your site, it wants to install an active x component named "name.dll". this component is loaded by core.js. The component then tries to fetch the availability information of Microsoft Office Communicator. I don't think your anonymous users will use this functionality. ;-)

Let's have a look at the problem:

In case of performance optimization you should never load core.js in anonymous WCM scenarios. SharePoint also tries to load other unnecessary stuff.

A nice way to avoid this is the MossCleanup HTTP Filter. Information on how to implement this: http://www.ie-soft.de/blog/PermaLink,guid,968b0588-f306-467b-be51-54f7a8f2079d.aspx

Fallback: If you need the core.js for any reason, just add this piece of javascript to your masterpage and "name.dll" wont be loaded anymore.

<!-- Avoid calling name.dll ActiveX -->

<script language="javascript" type="text/javascript">

function ProcessImn(){}

</script>


28 Dezember 2007

Get or set the content type of a list item programmatically

Keith asked my last week, how you can get the content type of a list item. It's quite easy:

First you have the get the Guid of the field "ContentType". With this Guid you can access the properties bag of an instance of a SPListItem. There the content type is stored as a string.
SPListItem item = ...
Guid fieldGuid = item.Fields.GetFieldByInternalName("ContentType").Id;
item[fieldGuid] = "Document";
item.Update();

WebPartZone Adapter

Some weeks ago, the Accessibility Kit for SharePoint (AKS) was released. Unfortunately the AKS didn't solve all our problems. If you try to build a public website with Micorsoft Office SharePoint Server 2007 (MOSS) and pay attention to a clean structure of your HTML code (say: no table), perhaps this piece of code you help you!

When you place WebParts on your public website, then these WebParts are rendered in a HTML TABLE. This is because WebParts are placed in a WebPartZone and these are rendered with tables.

This behavior can be fixed with a ControlAdapter. Our ControlAdapter render the WebPartZone in a HTML DIV, if the user (logged-in or anonymous) is viewing the page. If the author edits the page, then the WebPartZone is rendered the "traditional" way. With this trick, we have a clean and modern HTML structure and the author have still all the (drag&drop-) functionality while editing the page.

Copy the following C# code in a file called AKS_WebPartZone_Adapter.cs and place it in the AppCode directory under your server root directory (like C:\Inetpub\wwwroot or C:\Inetpub\wwwroot\wss\VirtualDirectories\80).


Now you have to edit the compat.browser file which in the AppBrowser directory located in your server directory and add the following piece of code after the opening tag:
<browser refID="Default">
<controlAdapters>
<adapter controlType="System.Web.UI.WebControls.WebParts.WebPartZone"
adapterType="AKSAdapters.AKS_WebPartZone_Adapter" />
</controlAdapters>
</browser>