Archives

Archives / 2004 / December
  • SharePoint RunTimeFilter and audiences... an investigation

    In the web.config file of SharePoint Portal Server you find the line:

     

    <RuntimeFilter Assembly="Microsoft.SharePoint.Portal, Version=11.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" Class="Microsoft.SharePoint.Portal.Audience.AudienceManager" BuilderURL="audiencechooser.aspx" />

     

    I was wondering what this line was doing here, and what other things you can implement using RunTimeFilter configurations. Fired up Google… nothing. Fired up reflector, and after some disassembling I came to the following (possibly non-valid) conclusions:

     

    Microsoft.SharePoint.Portal.Audience.AudienceManager implements the interface Microsoft.SharePoint.WebPartPages.IRuntimeFilter.

     

    This is an interface in the Windows SharePoint Services namespace, so my assumption is that the runtime filter mechanism is also supported in WSS.

     

    The interface that must be implemented is:

     

    public interface IRuntimeFilter
    {
    // Methods
    [PermissionSet(SecurityAction.LinkDemand, Unrestricted=true)]
    bool CheckRuntimeRender(string IsIncludedFilter);
    [PermissionSet(SecurityAction.LinkDemand, Unrestricted=true)]
    ArrayList InitializeStrings(CultureInfo cultureInfo);
    [PermissionSet(SecurityAction.LinkDemand, Unrestricted=true)]
    bool IsFilterActive();
    [PermissionSet(SecurityAction.LinkDemand, Unrestricted=true)]
    string ValidateIsIncludedFilter(string persistedString);
    }

     

    What these methods exactly should do is not documented, so after some disassembling of Microsoft.SharePoint.Portal.Audience.AudienceManager:

    :

     

    public bool IsFilterActive()
    {
      if (PortalApplication.GetContext() == null)
      {
        return false;
      }
      return true;
    }

     

    So this filter is only active if there is a portal context, that means only for SharePoint Portal Server, not for WSS. Makes sense for audience manager because this functionality is only available on the portal.

     

    public bool CheckRuntimeRender(string isIncludedFilterOrg)
    {
    :

    }

     

    This method seams to do an intersection between the selected target audiences for a web part, and the list of audiences the current user is part of. This is probably done for each web part, because targeting to audiences can be applied per web part. This would mean that the RunTimeFilter mechanism is only there for web part filtering: is a web part displayed or not for the current user (anyone?). Intersection computation is done through the stored procedure DBO.OrgleMatchOrgleList. If there is an intersection the web part is rendered.

     

    public string ValidateIsIncludedFilter(string PersistedString)
    {

    :
    }

     

    Not sure what happens here… I think the PersistedString parameter is the string returned by the selection of the audiences. Probably a concatenation of audience ID's. There is some translation going on to guid's returning a new comma separated string of guid's.

     

    public ArrayList InitializeStrings(CultureInfo ci)
    {
    :

     

    :

    }

    Looks like this function does some initial initialization of a string table based on a culture… which is ignored in the AudienceManager. Still not completely understand the complex way things are implemented in this function, but the result is that the texts to be used for the functionality for targeting (the "Target Audiences" section in the "Advanced" part of web part configuration) is retrieved. Strings like "Target Audiences" and "Select" (for on the button).

     

    The aspx page specified in the RunTimeFilter tag (BuilderURL="audiencechooser.aspx") is hooked up to the button for the selection of the audiences.

     

     

    If you look at the hooked up pages for audience selection in the current implementation, you see the following code:

     

    <%@ Page language="C#"

    Inherits="Microsoft.SharePoint.Portal.SitePage,Microsoft.SharePoint.Portal,Version=11.0.0.0,Culture=neutral,PublicKeyToken=71e9bce111e9429c" %>

    <%@ Register Tagprefix="SPSWC" Namespace="Microsoft.SharePoint.Portal.WebControls" Assembly="Microsoft.SharePoint.Portal, Version=11.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> <%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=11.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

     

    <html dir="ltr">

    <head>

    <SPSWC:PageHeadTags runat="server" TitleLocId="AudienceChooserPageTitleText" OldExpires="0" PageContext="SiteAdminPage"/>

    <SPSWC:ExternalHtmlResourceElement runat="server" HtmlElement="Script" FileContext="SharedScript" FileName="audpicker.js" />

    </head>

    <body>

    <form runat="server" ID="AudienceChooser2" method="POST" action="AudienceChooser2.aspx">

    <Sharepoint:FormDigest runat="server" id="FormDigest" />

    <SPSWC:PageLevelError id="AudiencePageLevelError" runat="server" />

    <SPSWC:AudiencePicker id="AudiencePicker" SupportRuntimeFilter="true" runat="server" />

    </form>

    </body>

    </html>

     

    With the actual real implementation in the server control

    <SPSWC:AudiencePicker id="AudiencePicker" SupportRuntimeFilter="true" runat="server" />, meaning the class: Microsoft.SharePoint.Portal.WebControls.AudiencePicker

     

     

    A simple test reveals that only one entry of RunTimeFilter is allowed in the web.config. This is a pity, it is not possible to implement your own web part display filtering on top of the existing one. If you really want to this can probably be easily done by implementing a new filter and call in this filter multiple other filters. On the other hand: if you want to change this, you probably want to change this completely.

     

    I never was really impressed by the way that audiences were implemented. Can be that I don't really understand the intended way of usage;-) Some of my problems with it are (incomplete list):

     

    • Audiences are precompiled, so not "real-time"
    • Audiences are rules based on profile properties (coming from active directory), often there is already a company directory available in large organizations, and replication of all the needed information to the profile is not always the way you want to go
    • Due to the the restricted possibilities in the audience definitions you can make I always end up with way to many audiences. For example: if you have an audience definition depending on the country and office you are in, you have to define country*office audiences, instead of targeting to a country, and/or an office

     

    On top of my head the only places audiences are used are in listings and in web part targeting. Web part targeting can be overruled by implementing your own RunTimeFilter. For listings and the targeting in here you probably need to reimplement all the portal web parts showing listings because you have to implement your own filtering on listings.

     

    How it works with listing I did not investigate yet. Maybe a topic for a next weblog entry!

     

    If anyone has more info on this stuff, please reply!!!

     

    Disclaimer: all made assumptions are speculative, based on disassembling and (I hope) some common sense.

  • SharePoint lists... did you know?!

    I use SharePoint a lot... as a developer. Ok, our intranet runs on SharePoint, and I know my way around as a user (I did build a large part of it) but most of the time I REALLYwork with SharePoint I'm diving in the object model, programming against it. A few days ago I was scoring use-cases together with collegue developers for a huge SharePoint implementation for a customer. In those use-cases there was a description of some sorting functionality in a list that we thought would take a long time to implement. We called in the analist who wrote the use-case to blame him for writing way to difficult use-cases, and he looked at us as if we were really stupid. And he was right.

    As a developer you sometimes forget to look at the functionality that is available just out of the box. One of those things is the standard functionality that is available in the SharePoint lists. Most people knowledgable of SharePoint will think: what is your point? Didn't you know this? Why do you bother me with this: read the f*cking manual. For those other people who forgot to read the manual, I would like to enumerate some things about lists that are "out of the ordinary".

    Did you know that:

    • Lists based on the "Links" list have a "Change Order" option in the menu bar of it's views that allow you to reorder the list items
    • Lists based on "Tasks" and "Issues" have an "Assign to:" field that is a lookup to users in the UserInfo list for the web the list is on. This list contains all users that ever visited the list. What does this mean:
      • Users who did not visit the web yet are not in the list
      • Users who ever visited the web site, but whom's account is now removed is still in the list (Should be like this: task/issue can be assigned to user that is now gone, if you edit the task/issue to change something, the user shouls still be in the list, otherwise it must always be reassigned on edit.)
      • System accounts that crawl the list are in the list (we filter those out using the MacawSharePointSkinner)
    • Lists based on "Issues" have an option to sent the "Assigned To" person a notification e-mail (General Settintgs ->Email Notification) on changed item or when ownership is assigned.
    • Lists based on "Issues" have a "View reports" action with reports to track issue trends
    • Lists based on "Contacts" have "Export Contact" functionality in the menu of an entry that created a vcard file
    • Lists based on "Contacts" can "link to Outlook", this creates a read-only contacts list in outlook, with in each item a link to update the contact. This list in outlook stays up to date automatically
    • Lists based on "Contacts" can import contacts from the address book
    • Lists based on "Events" can "link to Outlook", this creates a read-only calendar in outlook, with in each item a link to update the event. This list in outlook stays up to date automatically
    • Lists based on "Discussion" support threading on items, and that this list sucks for discussions (in my opinion). We rewrote the new/edit/view pages to se things like the thread you are replying on, the complete thread of a single discussion item, see the newest discussion thread first. This makes it usable.
    • List items can have multiple files attached
    • There are no events available on lists, only on libraries. When I asked Mike Fitzmaurice about this on the PDC 2003 he answered that it was due to lack of time. There was a big launching customer who needed events on libraries, so this was implemented.

    All this functionality is somewhere available in the list definitions, so if you define your own template you can combine all this functionality!!

    Maybe I will write some more on the libraries (Forms/Documents/Pictures) in the future. Who knows...

    Are there any other hidden gems out there that is good to know about... let me know in a response on this post.

  • WSS logging level

    A few weeks ago I had a problem with WSS. Really strange things happened, but nothing was written to the eventlog. After some searching I found the logging file written by WSS, but the amount of information logged is really minimal. SPS has much more extensive logging, see manual, but WSS specific things are even on an SPS server logged to the WSS logging mechanism.

    After some searching I found on http://wss.sharepointtips.com/pages/III%20-%20Administration.aspx on Q: 04 the following text:

    "STS 1.0 had logging to C:\WINNT\system32\LogFiles\W3SVC1 (and W3SVC2, W3SVC3 etc.)

    WSS has (RTM) a configurable registry key that you can set to control how verbose the logging is.
     
    Critical events will be logged to the application log in the event viewer.
     
    The stsadm.exe comman line utility uses a log file called stsadm.log which is stored in the temp directory of the person running this utility.
     
    The log for the w3wp process (w3wp.log) is stored in the windows temp directory."
     
    As stated in this text, the logfile can be found in c:\windows\temp\w3wpMSSharePointPortalAppPool.log (in my case). This name depends on name of the identity pool your SharePoint site is running under.
     
    Especially the sentence "WSS has (RTM) a configurable registry key that you can set to control how verbose the logging is." puzzeled me. We opened a call to Microsoft Support or more information on this and got back the following answer:
     
    Location to change the LogLevel
    HKEYLOCALMACHINE\SOFTWARE\Microsoft\Shared Tools\Web Server Extensions\6.0
    Change the LogLevel to Value Data of 9

    The Loglevel is by default set to 0. If you look in this container you also find the key MaxLogSizeKB. I assume this specifies the maximum log file size, don't know what happens if this size is reached.

    More logging is available after setting this registry key, not overwhelming, but more than it was before! Strange those kind of things are not just documented....

     

  • NAnt: concatenate filenames

    I'm currently constructing some NAnt build scripts for our continuous integration build environment for SharePoint development. One thing  I want to do is that on the development server is that I want to install compiled web part assemblies and their references assemblies using the InstallAssemblies tool. This tool has in the command line version the option to install a set of assemblies using the "assembly:x,y,z" parameter. This parameter needs to have the assembly files separated by ','. I concatenate those filenames using the following code:

    <project name="concat.test" default="concat.filenames" basedir=".">
     <target name="concat.filenames" description="concatenate filenames">
      <property name="concatenated.filenames" value=""/>
      <foreach item="File" property="filename">
       <in>
        <items>
         <include name="files*.*" />
        </items>
       </in>
       <do>
        <property name="concatenated.filenames" value="${concatenated.filenames}${filename},"/>
       </do>
       <!-- now remove the trailing ',' -->
      </foreach>
      <property name="concatenated.filenames" value="${string::substring(concatenated.filenames, 0, string::get-length(concatenated.filenames) - 1)}"/>
      <echo message="${concatenated.filenames}"/>
     </target>
    </project>

    Result: [echo] C:\projects\NantTest\files\file1.txt,C:\projects\NantTest\files\file2.txt,C:\projects\NantTest\files\file3.txt

  • SharePoint custom solutions: Storing extra data in SharePoint

     

    When developing SharePoint solutions there is often the need to store extra information at certain levels in SharePoint. In this blog I enumerate some of the possible levels where extra information can be stored:

     

    WSS list: just add an extra field, easy!

     

    Web: SPWeb object has a property called… properties. This property is of type

    Microsoft.SharePoint.Utilities.SPPropertyBag. This property bag is an extension of the .Net framework class System.Collections.Specialized.StringDictionary, a hashtable with the key strongly typed to string. In this property bag you can store any object by name. Don't forget to call the Update method on this SPPropertyBag to persist your modifications to this property bag to the database. Because information is stored persistently to the database, I assume the object stored in the property bag must be serializable.

     

    Site: It is sometimes still difficult to differentiate between what is a site and what is a web in SharePoint terms.  From the manual: "The SPSite class represents a collection of sites on a virtual server, including a top-level site and all its subsites." This collection of sites are called the webs. Each SPSite has at least an SPWeb connected to it, you can get this web using the OpenWeb() method. So there is no need to store extra data at the site level, store it in the corresponding web as described above.

     

    Area: The Portal area's have a fixed set of extra properties that can be assigned. Have a look at the Bool1..Bool3, DateTime1, Int1..Int3, NText1, NVarChar1..NVarChar4 properties (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/spptsdk/html/cArea.asp). Use those properties to store extra information, and don't forget to call the Update method after setting those fields! This information is quite restricted, but can be used for fast querying on area's. Each area also has a connected SPWeb accessible through the Web property, where the property bag can be utilized as described above.

     

    Area Listing:  The Portal area listings extensibility is patterned along the same lines as the area. Again we have properties Bool1..Bool3, DateTime1, Int1..Int3, NText1, NVarChar1..NVarChar4 (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/spptsdk/html/pAreaListings.asp).

  • SharePoint search querying documented..

    There was already some information available on the SQL Search syntax of SharePoint Portal Server Search.

    Some of this documentation was for the old version of SPS2001, but did still apply:

    Deep Traversal of SQL Full-Text Extensions, by Margriet Bruggeman, Nikander Bruggeman (http://www.asptoday.com/Content.aspx?id=1410). This link is on a pay-site.

    Now there is some new documentation available: Microsoft SharePointPSSearch SQL Syntax (Preview). Have a look at: http://www.microsoft.com/downloads/details.aspx?familyid=d6a10783-a4e4-4463-8444-f88be48760b3&displaylang=en

    Quote:

    This download includes a preview of the reference documentation for Microsoft SharePointPSSearch the SQL Syntax used for Microsoft SharePointPSSearch Full Text Search with Microsoft Office SharePoint® Portal Server 2003. Look for updates to this documentation in the Microsoft SharePoint Products and Technologies 2003 Software Development Kit (SDK).