Sunday, December 17, 2006

CAML Queries return all items despite of filter

This had me puzzled for a while, so let me spare you the agony.

I was writing code that queried a list using the GetListItems function of the SPList object. The query I was using was from the U2U Caml Creator (great application, even with the bugs) and was working on that application perfectly - filtering my list to return only the items I wanted.
But in my web part the query would return all items in the list, ignoring the filter I set.

After some tests I found the problem. Apperantly the SPQuery object automatically wraps your query with the "<query>" tag, and since the U2U Caml Creator application also generates queries with the "<query>" tag, you actually have two "<query>" tags in your query, which makes sharepoint ignore the filters you set in the query.

So next time you are using the SPQuery object, remember the Query property should receive a CAML query, but without the "<query>" tag. Only whats under it.

Notes about Workflow

Lately I had to write some workflows in visual studio for the first time. I loved the interface, and the richness of options. I cant wait until I get to work with either K2 or Captaris and see how they enrich my workflow environment, but for now the built in workflow action that come with .net3 seem very cool.

I did have some problems though. On my development machine the "delay activity" wouldn't finish.
The delay activity is a cool way to tell the workflow to stop and wait for a specific time. We used it for task reminder setting - the workflow was supposed to wait until the task was due, and then send an email to the task owners. The way to do it is simple - in the delay activity "initializeTimeOutDuration" event you check the task list item "due date" field, and then calculate the time from that date to the "now" date, and set the "TimeoutDuration" property of the activity to that timespan.
The problem was- it didn't work!
After much research I got another machine going, and deployed the workflow there. works like a charm. I noticed that on my dev machine sharepoint is out of synch with the system clock. while the system clock said it was 10am, sharepoint was claiming it was 11am. I guess that messed up the workflow timer. I still don't know how to fix this.

Another interesting thing - The delay activity seems to operate in 10 minutes time units. There is no point in setting a delay activity to 1 second as opposed to 2 seconds or 10 seconds. both will fire at the next timer event which seems to occur once every so often (10 minutes? who knows?). So don't count on the engine for realtime applications (-:

The last thing I wanted to note was that the sharepoint "logToHistoryListActivity" is a great function to use to debug your workflow without going into code, not to mention it can be used to let users know the status of the workflow and what was done. But beware - appearntly each once of these activities can only store a limited amount of characters (my guess is 256, but I didn't check). So limit your logging to a minimum, and don't expect a stack trace to be properly logged there.

Did you notice? Microsoft.com went MOSSy


In case you didnt notice, Microsoft US site went all MOSSy on us. I guess they will be migrating regional sites soon, but now if you click the "change" button at the top, you get to a non-moss site and the Australian site is still the old one.






While I like the top of the page (regardless of the brown Zune which I think is pretty...hint hint if anyone is looking for a Hanuka gift for me), I think the grouping at the bottom look out of place from the look and feel. The font just isnt right. Also, the links at the top have a very strange on hover behavior - they get a dotted underline instead of the usual regular underline. At first I thought there may be some text wraped below the words - so strange!


The search isnt done by MOSS (big surprise? not really) and for some reason the "skip to contents" link (accessability!) is missing.


Since microsoft.com is one of the most viewed pages on the internet, I think its a very brave move by microsoft to MOSS it. The performance seems ok, and they probably did an impressive farm deployment there. I would love to read about it!

Thursday, December 14, 2006

Fixing the Sections Bug in the Edit User Profile Screen


The edit user profile screen is where users go to edit their details in the profile database.
In this tip I will show you how to get a nice looking screen with sections and headers, just like this:


If you ever looked at the administration page of the profile database properties, you must have noticed the "sections" - you can group properties by sections, so for example all contact information properties such as "mobile phone" and "phone number" and "Home address" are under one the "Contact Information" heading , while additional information such as "skills" are under the "Additional information"


Example of section grouping of user profile properties

What puzzled me is that this doesnt effect the "edit details" screen. I found that if you edit the EditProfile.aspx page (located at "Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\LAYOUTS\editprofile.aspx") you can set the edit the "ProfileEditor" control to have "ShowSections=true". This makes the edit profile page display the properties grouped by sections.


I actually liked the following combination of properties for look & feel:



ShowEditToolbar="true"

ShowMappedIcon="true"

ShowPublicIcon="false"

ShowSections ="true"

ShowWarningIcon="false"

MoveEditablePropertiesToTop = "false"

ShowOnlyVisibleOnViewer="true"

ShowTitle = "false"

UseProfileStyles = "true"


What messed things up for me is a Microsoft bug with this control having to do with the column span of the section header. The sections are rendered with column span of 3, when the rows below them have column span of 4. This makes for a very ugly appearance, when the section header is "cut off" at the end.


To fix that, I wrote a small script that I embedded in the file, just after the <table> closing tag. The script finds all the "div" elements that have the "ms-WPTitle" class, and then changes the columnspan of the parent "TD" element to 4.


  • Important - For the script to work, you also have to add an ID to the table that holds the edit profile control. I used in the script id="tblMain".


  • Important - The script has to be below the table, but within the asp:content block. dont try to place it at the very bottom of the page, or it will crash.


  • Important - Like always, I suggest you backup the original file before editing it.

I hope someone else will find it useful!


<script language="javascript">
function SetWPTitleToColspan4()
{
cssClassName = "ms-WPTitle";
var divs = tblMain.all.tags("DIV");
var currentDiv;
for(currentDiv=0;currentDiv<divs.length;currentDiv++)
{
var div = divs[currentDiv];
if(div.className.indexOf(cssClassName)==0)
div.parentElement.colSpan = 4;

}
}
SetWPTitleToColspan4();
</script>



Tuesday, December 12, 2006

Highest SharePoint Expert in Australia

Over the weekend the whole sharepoint team from Unique World (Canberra division) went to climb the highest peak in Australia. you can read about it in my personal blog if you want the whole grueling story including many pictures.


The team includes our esteemed leader & SharePoint MVP Gayan Peiris. But I was still the highest expert in Australia because he wouldnt climb to the top of the stone like I did.





The highest SharePoint Expert In Australia - just over 2228m



The Second Highest SharePoint Expert In Australia

Webparts on List Forms

Just a quick update on something I noticed that changed from beta to RTM. In beta, if you tried to add a web part to a list form (edit or new form) using SharePoint designer, the page would crash. So we had to develop our code in web controls instead.

In RTM the page is not crashing and we can keep the code in a web part.

Good news.

Thursday, November 30, 2006

Changes that you make to the "List View" Web Part are not retained after you save the site as a template

For those of you without the time to read the original article, basically what happens - when you save a site as template, the settings for web parts displaying lists are not always saved.

I had planned to post about this today and rant about how microsoft missed this, but they beat me to it and acknowledged this bug in the KB Article.

I just hope they give us a quick fix and we dont have to wait untill service pack. This really "uglies" our solutions.

Sunday, November 26, 2006

Plan for administrative and service accounts [Office SharePoint Server]

Ran across this great technet article explaining exactly what accounts you will need to set up sharepoint in production, and what level of permissions to give each one.
http://technet2.microsoft.com/Office/en-us/library/f07768d4-ca37-447a-a056-1a67d93ef5401033.mspx?pf=true

Search Highlighting For MOSS2007 (and 2003) - Update

This is an update to a year old post about a product that I helped write - the SharePoint Search String Highlighter. Apperantly my friends in KwizCom have added support to MOSS2007!

Before you say "but moss has search highlighting", let me remind you that this solution also highlights in the documents (word and pdf), and can also help you solve a problem that is usual with search results - make sure the links open in word and not in the browser (I hate when that happens).

So take a look - tell me what you think...

Wednesday, November 22, 2006

Announcing the SharePoint Tips Utility Pack!

update (13.2.2006)
I moved the download and released the open source to a codeplex open source project.
I also released version 1.1 which has some improved features on the field settings screen.

update (1.12.2006) - I moved the utility pack download to a better host- the Canberra SharePoint User Group site (which is where the application was first announced).
Please be patient when clicking the download link, as the user group site was not meant to be a file host and I guess the download can take a while to begin - but its a small file so when it does begin it wont take long.
I am also in contact with Microsoft to get the source code on codeplex - so stay tuned!

Its that time again - time for me to give away something I did for myself to the public.

This time its a pack of small utilities made to make life easier for me as a sharepoint 2007 deployer\administrator\consultant. I am constantly working on small utilities and scripts like these, and now I packaged some of these and I am letting you download it for free. At your own risk.

So hurry and download the SharePoint Tips Utility Pack. I will move the file to another file host service when I find a better one.

Oh, before I forget- to run this application you must run it on to the sharepoint server itself, and to set the trust level in the web.config file to "Full" or sharepoint will not allow the application to get to the data...

Here is what you get in the pack:

  1. A utility to push web parts to existing sites
  2. A utility to create lists in existing sites
  3. A utility to delete sites recursively
  4. A utility to change list fields settings

I also plan to add to it my utility to register event handlers to lists - coming soon!
So please remember - I am open to suggestions and when I am able I will release the source code for the community benefit. kick it on SharePointKicks.com

Sunday, November 19, 2006

Help needed to design a community tool

Below is an image of a tool I have been working on for my own use, and I thought to release to the community as open source utility.

The objective - deploying webparts to web part pages in sites, using code and not using masterpages (not all sites have same master page, and also if you use master page to deploy a web part you complicate changing one site in the bunch...) in sharepoint 2007.

So the screen shot is of the options I came up with so far to answer what I needed to do and set. If you have any more ideas for options to put on the screen - comment to this article and I may find the time to include them before I release this to the public!

Waiting for your commnets!

Thursday, November 16, 2006

Happens every time - adding a web part class to a project

I hate it when I dont learn from my bad experience...

When I have a solution with a web part and I want to add another web part to the same project I just right click the project, select "Add" and choose "Class". Then I tell the class to inherit from "WebPart" and proceed to program my code.

And when I get to deploying it - the new class isnt shown in the new webparts gallery!

why?

because I forget every time to mark the class as "public" - when Visual Studio creates a new class in a project, the default is just "class newwebpart".

So the lesson for today - dont beat yourself going over the web.config file - just make sure the class is marked public.

WSS & MOSS RTM are out to download

Well, if you have been following my blog you probably noticed that I avoided linking to new downloads of the beta as they got released. I hate it when all bloggers say the same thing at once and my RSS reader shows 600 new articles- all links.

But this is different. SharePoint 2007 is available as a public download (trial version) and so is WSS3.

  1. Microsoft Office SharePoint Server 2007 Trial Version
  2. Windows SharePoint Services 3.0

Happy days...

And just so this post isnt just a lame linking post I will update you that I am working on part II for my popular "Simple Code Samples" article. I have some code samples on security, and on lookup fields that I feel are essential to any sharepoint developer.

Also coming soon (very soon) - some new free downloads of some tools I have written for some of my projects to make my life easier.

See you soon!

Monday, November 13, 2006

Answer to comment - how to specify a category to a site template

Someone name "Seth" asked me today how to specify a category for a site template. Unfortunately Seth forgot to leave his email or contact number, so I will answer publicly.

I dont know how to do it for a saved template (saved by the "save as site template" function in site properties). But I do know that using Site Definitions its possible. Site definitions are registered by adding an xml file under "C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\1033\XML\" folder. The xml schema that declares a template looks like this:

<Template Name="SPSSITES" ID="34">
<Configuration ID="0" Title="Site Directory area template" Type="0" Hidden="FALSE" ImageUrl="/_layouts/images/template_site_dir.gif" Description="This template creates a site that lists important sites in your organization. It includes different views for Categorized Sites, Top Sites and the Site Map." DisplayCategory="Enterprise" />
</Template>

Notice anything bold? thats where you choose the category for the site template.
Using the new Visual Studio 2005 Extensions you can save a site into a site definition, and then change the xml as needed.

Questions?

Thursday, November 09, 2006

Sharepoint list forms and adding web parts and our Sub tasks solution

Lately I have been testing adding web parts to list forms and discovered an interesting thing:

I have been involved with doing a nice solution for sub-tasks in sharepoint 2007 and the way we did it is develop a web part to put on the "display form" that queries the task list for items with the "parent task" field pointing at the current displayed task.

Adding that web part to the display form wasn't a problem - just open the form in Sharepoint designer, add a web part zone to the side and drop the new web part there.

Then I wanted to add a web part to the "new task" form, that gets from the querystring which task it should connect to, and set the value to the "parent task" field automatically. To my surprise, I found that if you try to put it on the form, the page crashes with an error.

Before you say "Ishai, you write lousy code" I have to stop you and say I tried adding default sharepoint web parts as well, and the end result of the research is that when you add web parts to a page that has either the "edit" or the "new" list forms - the page will crash.

Whats the workaround? we moved the code from a web part to a web control, and manually added it to the page. Works like a charm, and now we have a viable tasks-sub tasks solution. I will publish what I can of the code after testing.

Here is what our solution looks like:
Creating a new task:

View that task, currently no sub tasks were created:

Click the "Create sub task" link and you get to the "new task" page again:

View the root task again, this time you see the sub task in the side web part:

Another option to create the sub tasks - through a context menu:

I want to mention that two developers have been working with me on those web parts- I want to thank Adam Tibballs and Steven Pavlovic for their time and effort.

Tuesday, November 07, 2006

Synchronous list event handlers ruin datasheet view

I have written a synchronous list event handler, using the ItemUpdating event to manipulate some data. Now when I try to edit data in the datasheet view I get conflict errors, and I cannot save my changes. Using the regular edit form works. I guess this is a problem in the product, and I hope it will be fixed in RTM. However, since I couldn't find anything about it on the news groups, I guess no one reported it and MS may not know about it.

On a similar matter, some people have been telling me that my code sample for updating list items without firing the events doesnt work for them. I suspect the problem is with different events. The synchronous events ("ing"s) require you to edit the afterproperties, while the a-synchronous ones ("ed"'s) require you to edit the item itself.

Here is a code sample from an event handler I wrote. its not perfect, but its a good sample for what you need to work on.

this.DisableEventFiring();
SPList list; SPListItem item;
switch (properties.EventType)
{
case SPEventReceiverType.ItemAdded:
list = properties.ListItem.ParentList;
item = list.GetItemById(properties.ListItemId);
item[siteLinkFieldName] = itemSiteWrapper.SiteLinkFormatted;
item.SystemUpdate(false);
break;
case SPEventReceiverType.ItemAdding:
break;
case SPEventReceiverType.ItemUpdated:
list = properties.ListItem.ParentList;
item = list.GetItemById(properties.ListItemId);
item[siteLinkFieldName] = itemSiteWrapper.SiteLinkFormatted;
item.SystemUpdate(false);
break;
case SPEventReceiverType.ItemUpdating:
properties.AfterProperties[siteLinkFieldName.Replace(" ", "_x0020_")] = itemSiteWrapper.SiteLinkFormatted;
break;
}
this.EnableEventFiring();

Monday, October 30, 2006

Preventing event handler recursion

One of the problems I had with list event handlers was event recursion.

I wrote an event handler to handle updating items. I wanted to check some values, and then set a value in a field based on a set of rules. The problem was- when I set the value of the field and updated the item, the ItemUpdated and ItemUpdating events fired up again, and again my code updated the item and so on and so on. I also wanted to avoid having the list item change version number following my code-update. that update was supposed to be part of the version that the user just created by updating. Otherwise, every user update of the list item would bump the version number twice! Similarily, I didnt want the code to show that an administrator changed the item. I wanted it to look as if the user did the change to that field.

So after some research, here is my solution: item[fieldnamehere] = fieldvaluehere; this.DisableEventFiriing(); item.SystemUpdate(false); this.EnableEventFiring();

This piece of code updates the item without firing the current event handler events, and doing the update using the SystemUpdate(false) method ensures that version number doesnt increase and the update is considered as if it was part of the user's update.

Do you like the new look? check out the new options!

I moved to blogger beta, which means I now have label support, so you can browse my articles better using the "Labels" links on the right of the screen. Also you will note that the archive is more user friendly!.
I Just wish that they would add RSS to the labels so that people can register to each category seperatly. I guess thats why they call it labels instead of categories...maybe in the future.

I would like to draw your attention (especialy my RSS readers) to a new link on the side of my blog here - a link to a job network. This is an interesting thing our friend from www.thedailywtf.com is trying - a network of people who read blogs to help each other get jobs.
The idea is simple- if you are reading my blog, it means you care enough about sharepoint to come to my site and read about it. This probably means you are a good sharepoint employee and employers are looking for people like you.
Face it - the very fact that you are reading my blog (or any tech blog) is a recommendation by itself.
Thats what HiddenNetwork is all about - connecting active & passive people in the community. And since the employers are also going to hear about that site from bloggers, it means that you stand a better chance to find work in a decent working place.

So if you are interested, and if you are looking for developers or consultants, go there and post an ad. I dont care if you use my link or not (I do get money if you do) since I am not blogging for a living like others do, but what I do care about is how damn hard it is to get good employees these days!

Saturday, October 28, 2006

Another shameless plug - SharePoint-Desktop synchronization solution For 2007 and 2003

I have to tell you about the new product from my good friends at KWizCom (ok, not so new - but I didn't have a chance to check it before now).

Their new product (ShareGO) is a great solution to synchronize documents from SharePoint 2003 and 2007(!!!) document libraries. They add a button to Internet Explorer: This allows you to configure a 2-way sync that includes:

  • Download new/updated server files
  • Upload locally updated files/local new files
  • Manage collisions - files that were updated both on the SharePoint server and locally.
  • Provide local recycle-bin for server-deleted files

Check out their web site. They have some movies that show how the product works, and I noticed a new support option in their site- you can chat with them and ask them questions.

A last note - if you have some recommendations for products you want me to review, let me know (comments to this blog are always read!).

Thursday, October 26, 2006

GAC "Access denied" Solution + Free "post-build" Script for Event Handlers

I have been working on an event handler, and I wrote a nice little post-build script to install it everytime I build it:

path = "E:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bin\"
gacutil.exe /if "$(TargetPath)"
copy "$(ProjectDir)\app.config" "C:\WINDOWS\ASSEMBLY\GAC_MSIL\$(TargetName)\[ASSEMBLY_VERSION]__[ASSEMBLY_PUBLIC_TOKEN]\$(TargetFileName).config"
RecycleAppPools.vbs

  1. Note that you have to replace some things in the code -[ASSEMBLY_VERSION] and ]__[ASSEMBLY_PUBLIC_TOKEN]
  2. Note that I have a configuration file called "app.config" that I am copying into the GAC after deploying the dll.
  3. Also note that I have my "RecycleAppPools.vbs" file in the .net sdk bin folder. This script recycles all application pools automatically, and takes less time than an IISReset.
    To create this file, create a new text file in the bin folder and paste the following code (rename the file to "RecycleAppPools.vbs"):
    Set locator = CreateObject("WbemScripting.SWbemLocator") 
    Set Service = locator.connectserver(strServer, "root/MicrosoftIISv2") 
    Set APCollection = Service.InstancesOf("IISApplicationPool") 
    For Each APInstance In APCollection 
        APInstance.Recycle 
    Next 

All was well and good, but suddenly I began to get errors - the GAC wouldnt let me install the DLL and would tell me 'access denied' when I tried to delete it from the GAC or replace it.

After some internet research I found the solution - stop the indexing service.

Now my little script is running smoothly, and I am developing and debugging my event handler with no problems.

Oh, yeah - I wrote a small application to register the event handler to a list. Anyone interested? I can publish it - it supports both command line operation, and a GUI interface.

Back from vacation, and Shane gives us office web parts!

For those of my readers who have been wondering why I havent posted anything in the last several weeks, it is because I was visiting family and friends in Israel and therefore did not discover anything new about sharepoint.

I returned to find that Shane (a sharepoint mvp) has discovered something I was worried about - how to add the office web components web parts (pivot chart, pivot table and worksheet) to MOSS2007

  • First find the cab file (microsoft.office.dataparts.cab) for the web part from a 2003 server
  • Copy the file to the 2007 server
  • Run the following command on the 2007 server:
    stsadm.exe -o addwppack -filename "c:\program files\common files\micrsofot shared\web server extensions\60\wppacks\microsoft.office.dataparts.cab" -globalinstall

I will soon be back with my own sharepoint tips, so be patient!

Monday, October 02, 2006

Creating a "Search Results Web Part" that searches on parts of the words

Here is the problem - We are using the profile database to create a phonebook application. SharePoint search only finds people if you type an exact match of the person name. For example, Searching for "Isha" will not bring my profile back since my name is "Ishai".

My customer wanted a prefix search so that searching for the beggining will return all people begining with the letters. Also, searching for parts of other properties such as job description should do the same (example - searching for "cons" will return anyone who is a consultant)

After much research, here is my solution:
Basically, what I do is override the built-in search result web part, and then modify the search query it runs. The only downside for this is that the default web part doesnt use XSL to format the results and doesnt have all the cool properties that the "PeopleCoreResultsWebPart" have. But with some work you can add the needed properties yourself.
  1. Create a new web part project
  2. Override the "Microsoft.SharePoint.Portal.WebControls.SearchResults" control
  3. Override the "OnInit" event (or, alternatively you can override the "GenerateQueryString" event)
  4. Add the following code:

    protected override void OnInit(object sender, EventArgs e){
    //add the wildcard support so that we will find everyone who starts with the typed keyword
    this.QueryTemplateWherePart += @"OR CONTAINS(#WeightedProps, '""%__keywordinputnoboundaryquote__%*""')";
    //add the filter to search only for people and not documents or page
    this.QueryTemplateWherePart += @"AND ""DAV:contentclass""='urn:content-class:SPSPeople'";
    base.OnInit(sender, e);
    }

Here is a sample of a class you can use:
using System;
using System.Data;
using System.IO;
using System.Web;
using System.Collections;
using System.Xml;
using System.Xml.Xsl;
using System.Xml.Serialization;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using Microsoft.Office.Server.Search.Query;
using Microsoft.Office.Server.Search.WebControls;
using Microsoft.Office.Server.UserProfiles;


namespace SPSTips.SharePoint.WebParts
{
    [XmlRoot(Namespace = "SPSTips.SharePoint.WebParts")]
    public class PeopleSearchResultsWebPart : Microsoft.SharePoint.Portal.WebControls.SearchResults
    {
        protected override void OnInit(object sender, EventArgs e)
        {
            //add the wildcard support so that we will find everyone who starts with the typed keyword
            this.QueryTemplateWherePart += @"OR CONTAINS(#WeightedProps, '""%__keywordinputnoboundaryquote__%*""')";
            //add the filter to search only for people and not documents or pages
            this.QueryTemplateWherePart += @"AND ""DAV:contentclass""='urn:content-class:SPSPeople'";
            base.OnInit(sender, e);
        }
        
        
        protected override void CreateChildControls()
        {
            Label lbl = new Label();
            lbl.Text = this.QueryTemplateWherePart;
            lbl.Attributes.Add("style", "display:none");
            this.Controls.Add(lbl);
            base.CreateChildControls();
        }
   }
}
update - I found that the web part doesnt support property search and I am working on a workaround. wait for updates.

Wednesday, September 27, 2006

Synchronous Add List event (ItemAdding) will not give access to item properties

UPDATE:

I have had a chance to look into this again now, and found that indeed it is possible to access and change properties in ItemAdding, if you are doing it through the "AfterProperties" hash table of the event, and not through the list item.
Some things to note:
During ItemAdding, there is no SPListItem object to refer to. It is null in the event properties, because to get an SPListItem a record for the item should be in the database, and during ItemAdding nothing has been written to the database yet.
After ItemAdding, the item is added to the database. When it is added, the values from the AfterProperties are applied to it. If you try to add a property to that hashtable that doesnt exist in the list definition, the user will get an error that the field isn't installed correctly. You may encounter this if you don't use the internal name of the field when you set the AfterProperties.
The moral of the story - Use the AfterProperties in ItemAdding, and when you use it to get or set a field, make sure you use the field's internal name.
That said, my argument with Sahil (see below in the original post) remains - you cannot use the SPListItem, because one cannot exist. His sample code modifies the item that was added before the current item, and not the current one.

Here is a sample code that modifies one of the fields in the ItemAdding event. In this example we have a links list, with a custom column called "Tool Tip" (internal name is "Tool_0x0020_Tip") and we want to set it automatically to the title of the link the user picked:

public override void ItemAdding(SPItemEventProperties properties)

        {

            string toolTipFieldInternalName = "";

            using (SPWeb web = properties.OpenWeb())

            {

                toolTipFieldInternalName = web.Lists[properties.ListId].Fields[TOOL_TIP_FIELD_NAME].InternalName;

 

            }

 

            string urlVal = properties.AfterProperties["URL"].ToString();

            SPFieldUrlValue val = new SPFieldUrlValue(urlVal);

            string desc = val.Description;

            properties.AfterProperties[toolTipFieldInternalName] = desc;

        }

Original post: (was posted during Beta2) Ok - here is an update to my "Bad news - synchronous list events bug (or missing feature)" post from August:

I reported this as a bug to Microsoft, and got a response that they "cant repro this on a newer build - please check on TR".
So I waited for TR, and checked again - no change! The properties of the new list item are simply not accessible.
I reported this to MS, and this time gave a full code sample so that they will be able to repro exactly what I was trying to do.
The answer came back that this is by design!

Microsoft has no plans of giving us developers access to list item properties in the itemadding event. All you will know is that an item is being added. You will notice that the SDK was also updated to show a sample code that checks the number of items in the list and shows a user an error if there are 150 items in the list. But checking the new item's properties can only be done in the "itemadded" event.

By the way, this means that Sahil's example does have the bug I pointed out - during itemadding, the item is not yet added to the list and is not available through list.Items[list.Items.Count-1].

People- I think this is big enough that we should gang up on Microsoft and clamor for them to give us the ability to check properties of list items. Write comments here if you agree and we will build us a petition!

Sunday, September 24, 2006

Trouble with Beta2TR

Oh boy, its been a bad day for me, and its not even 15:00! Last week my sharepoint shared services started misbehaving (luckily, only after a major presentation I had) and today I just couldnt run searches any more, and the user profile database was down.

Going into the shared services administration screen and then clicking "search settings" would give me an error that the search service is offline or the index is being moved, and trying to go into the profile administration would tell me the SQL server database is unreachable.
The event log kept saying that my user account (lets call him spsadmin) failed to logon: "Login failed for user 'DOMAIN\spsadmin'. [CLIENT: ]"
which is very strange since that account is a machine admin, and a SQL admin and DBO for all databases.

isnt that cool?

What havent I tried?
I tried changing the accounts, the passwords, the services..I even tried restarting the server (who knows...).
Finally, I am trying now to reinstall sharepoint.
What I am worried about is installing sharepoint beta2 and then installing TR, on a machine with office beta2tr. I hope no conflicts arise.
Wish me luck!

Wednesday, September 20, 2006

Free web part, as promised! - User profile Checker

As I promised a couple of days ago, I have published a new webpart for download, complete with source code.

The web part checks the user's profile for properties that are marked as "required" and if a user didnt fill in one of them, he is prompted to fill it in:

You can also choose to have the user prompted by a message box, or just automatically redirect him!


Here is the download:
As an answer to the comments I will explain some more:

The web part checks the properties that are not disabled, that are user editable or are administrator editable and are required.
The property may be mapped to active directory,

Monday, September 18, 2006

The cursed Site Directory Template in MOSS!

wow...been a long day batteling against the site directory site template. I filled so many bug reports I will have to go through the store tommorrow and get some bug spray!
Let me start from the beggining.

The "site directory" site template is a great template with some features to catalog sharepoint sites. It includes a large "create site" button on the top of the page, and has a "sites" list that holds the links to the sites created through the "create site" link, and stores meta data on them.

So I had an idea - create a new site collection with the root as a site directory, change the name "create site" to "create project" (since my customer wanted to create project sites - nothing to do with project management...long story, but project server is out of the question) and ask the user to add custom meta data on the "project" he is creating.

Well - happily Microsoft realised this was something sharepoint 2003 lacked, and are trying to fix it. When you edit the "sites" list, and add custom fields - the site creation page shows you those fields when you open the "create site" page.
bug number One
Site directory as the root site? go figure!
Apperantly no one thought that the site directory template would be used as a root site in the site collection. otherwise, how do you explain the fact that the "create new site" button is rendering a wrong link when the template is used that way.
instead of writing the link as "/_layouts/newsbweb.aspx" it renders "//_layouts/newsbweb.aspx". This one should go directly to www.thedailywtf.com.

bug number Two
Complex controls? who wants that?
so you wanted a field called "due date". and you wanted that to be (hold your breath) of type date. you didnt expect the date picker control, did you?
...
oh, you did. pity. date fields are rendered as text boxes in the create site dialog.
And you created a lookup with a multiple selection enabled. so what?! you will still get the look up field rendered as a combobox (allowing only one item to be selected). and say thanks its not a text box like the dates!

bug number Three
Still with the custom fields. So I wanted to force a user to fill in one of the fields. is that too much to ask? but no...validation doesnt work on the cursed page.

bug number Four
Did i mention the fact that I added a lookup to another list, and set it to allow multiple selection in the "sites" list? I am sure I did. Such a scenario is probably to far-fetched, since when you fill in some data in the list, you suddenly see in the list view web part strange text next to every selection in that field: "<!-- #RENDER FAILED -->"
I wonder what thats about...

bug number Five
You have got to be kidding me!, web part communication? with a list called "sites" in a site directory template? what are you talking about???
Well - you can connect two web parts, and have one of them be the "sites" web part, and even have that one as the receiver.
but...
if the receiver "sites" web part only shows one field (the title field) I got a nice looking error: "web part error: web part sites did not implement the GetInitEventArgs".
Add another field, and viola! web part connection works again.

bug number SIX SIX SIX!
Oh, you expected sharepoint to actually store the metadata? how bizzare!
yep - what ever you do, the site meta data isnt added to the "sites" list. so long site directory.

I think I'm going to lay down for a while. tomorrow I am going to develop my own site directory list.

oh, wait - I forgot - I tried that today using the event handlers. and guess what? The bug where "itemadding" event doesnt give access to the item properties is still there. So I cant catch the event of an item being added to the "sites" list and create a site based on the metadata. I will have to create my own aspx page to do it, and update the list.

I have an feeling this isnt going to be my week...Hey Microsoft - if I had wanted to be a developer I wouldnt have become a...errr...never mind, I guess it is my job to do workarounds (-:

Update
A lot of people are asking about how it is in RTM. Well, dont bother - I contacted microsoft about this during Beta, and they acknowledged that this is a known issue and the "site directory template was not meant to work like that".
Bummer.

Thursday, September 14, 2006

New setting for MOSS Indexing performance

Now that I am upgrading to the Technical refresh, I noticed a new setting for the indexing service - "Indexer Performance" which you can set to:
  • reduced
  • partly reduced
  • maximum

The description of this setting says:

"Indexing information can place a large load on the local SQL Server database and might slow down the responsiveness of the local SharePoint sites. However, reducing the maximum allowed indexing activity will slow down the speed at which items are indexed, and therefore might cause search results to be outdated. Use information about the local server load to select the appropriate indexer performance level. "

My nerd score

I am nerdier than 48% of all people. Are you nerdier? Click here to find out!

Its refreshing!

The beta 2 technical refresh is finally available to download.
During the last few days a lot of bloggers announced its coming, but I waited for it to actually happen. And today - it did.
I will have a look at the bugs I reported for the beta 2 and verify their status on the technical refresh, and report it here!

Wednesday, September 13, 2006

Microsoft Expression - Dont install on sharepoint machines

I recently downloaded and installed Microsoft Expression Beta 1.
From first glance it looked just like SharePoint Designer. I wanted to be sure of that, and tried to install designer on the same machine. guess what? I got an error.
ok- I removed Expression from my machine and then - my sharepoint started throwing script errors at me! "Library not registered" in every page!

After crying and reparing sharepoint and even restoring the entire "12" folder, I realized when the problem started (uninstalling expression) and I knew how to fix it- I installed sharepoint designer!
This time the installation worked, and afterwards sharepoint stopped antagonizing me.

So lesson of the days - never install Expression beta one on a server running Sharepoint beta 2.

Monday, September 11, 2006

Canberra Sharepoint User Group Surprise

I am doing a 15 min presentation on user profiles in MOSS2007 in the coming Caberra SharePoint User Group meeting, and I am planning a small surprise for the group. You had better be there!
Details to follow...

Wednesday, September 06, 2006

MOSS 2007 controls - have a bit of fun with the "people editor" form control!

Many times in my web applications I need to get input from the user about other users. For example, if I am creating a task-tracking application, the user will need to assign a task to another user.
Another example is when I developed an ASP.NET2 application that connected to SAP, and had to manage user travel details. Again, I had to let the users select other users to say "I want to create a new trip for that user" (something that happens often, when secrateries fill in the forms for the managers).

If you have SharePoint 2007, you can relax and stop developing a person selector box for these applications. SharePoint has a very nice control to do exactly that. In this article I will demonstrate how to use that control in a web part - see how in two lines of code I get a world of functionality!

The Code


The object we are talking about is called PeopleEditor and it is part of the Microsoft.SharePoint.WebControls namespace.
To add it to the web part, just declare it and add it to the web part controls. Example:
        PeopleEditor p;
        protected override void CreateChildControls()
        {
            p = new PeopleEditor();
          
            this.Controls.Add(p);
            base.CreateChildControls();
        }

The Results


The control renders on the page thus:

what do we have here? a text box that allows the user to write a user name, a "check name" button to verify that name, and an "address book" button to pop up a search window:

Here we can search for a person, and return the results to the text box we started from.

If the user typed a user name and used the "check name" button, he will be shown if the user name is valid or not, and may click on the invalid name to get "more names" options:

Now, how can we customize this to our form's needs?
you can:

  • use ".AllowEmpty" to specify if the user must fill the contorl
  • use ".AllowTypeIn" to specify if the user can type the wanted user name in the text box, or if he must use the search pop up
  • use ".MultiSelect" to specify if the user can select multiple people in the control.
  • use ".PrincipalSource" to specify where the control will look for users (if you have more than one source of users...)
  • use ".PlaceButtonsUnderEntityEditor" to specify if the "check name" and "address book" buttons will be on the same line with the text box, or underneath:
  • use ".SharePointGroup" to filter the people the user can select to be only people from a specific group defined in the site.

There are more options, but you will have to play around with them yourself. Unfortunately, Microsoft didnt release (yet) any documentation on the control and its use, so its up to us to find out and share our findings!!!
Have fun!

Thursday, August 31, 2006

My first WTF story published

Its not very funny, but its true...
read about my sad experience in WTF-U.

CAML builder for 2007 was released

Thanks to the gentlemen (and ladies) in U2U, the CAML query builder for 2007 is now released.
I recommend you go to the download page, and download the latest version there.

Tuesday, August 29, 2006

Common (and simple) coding tasks in sharepoint

Well, everyone went to teched last week and I was left at work stuck with a project with a strict deadline. So out of boredom I decided that I will compile a small snippet database for beggining sharepoint developers.
I see a lot of people in the microsoft public sharepoint developer forums asking these questions over and over again, so I thought I will save everyone some time by answering these right here.
Some people may say these are RTFM questions, since the SDK contains all of these examples, but apperantly people dont bother with the SDK, or find it confusing to navigate through. So here is my 2 cents.

The purpose here is to give some code samples to common tasks like:

  • getting a reference to a site
  • Iterating over all lists in a site
  • getting a reference to a list
  • getting a reference to an item in a list
  • getting a reference to the item's properties
  • getting a reference to a document and its properties
  • adding a new item to a list
  • modifying an item in a list

If you feel I should add to this list, let me know and I will write some sample code. However, please remember this is for simple, common tasks and I wont start giving application samples here.

So, lets get down to it!

Getting a reference to a site

Ok, you have a sharepoint site in a URL "http://server/sites/site" and you want to get the object of the site from its URL. What do you do?

using(SPSite mySite = new SPSite("http://server/sites/site"))
{
   using(SPWeb myWeb = mySite.OpenWeb())
   {
   }
}

Now you have the SPWeb object, allowing you to get information about the site you used in the URL. For example, iterating all lists in the site:

using(SPSite mySite = new SPSite("http://server/sites/site"))
{
   using(SPWeb myWeb = mySite.OpenWeb())
   {
      string linksHtml = "";
      foreach(SPList list in myWeb.Lists)
      {           
         string listLink = "<a href='" + list.DefaultView.Url.ToString()          + "'>" + list.Title + "</a>(<b>"+list.Items.Count+"</b>)<br>";
         linksHtml += listLink;
      }
   }
}

The above example also showed how to get a reference to a list by iterating over the lists in a site. But what if you want a specific list called "contacts"? The following will show you how to get the object for a list that you know the name of:

using(SPSite mySite = new SPSite("http://server/sites/site"))
{
   using(SPWeb myWeb = mySite.OpenWeb())
   {
      SPList contactsList = myWeb.Lists["Contacts"];
   }
}

Now lets iterate through the items in the list and get item's properties:

using(SPSite mySite = new SPSite("http://server/sites/site"))
{
   using(SPWeb myWeb = mySite.OpenWeb())
   {
      SPList contactsList = myWeb.Lists["Contacts"];
      foreach (SPListItem contact in contactsList.Items)
      {
         string contactLastName = contact["Last Name"].ToString();
      }
   }
}

Now some of you are saying - "what about documents?", to which I answer that document libraries are the same as lists (ok, there are some differences but we will leave that for future articles). To get to a document in a document library you can either use the code above to iterate through the library and its files, or, if you know the file's URL, you can do this:

using(SPSite mySite = new SPSite("http://server/sites/site"))
{
using(SPWeb myWeb = mySite.OpenWeb())
{
SPFile file = myWeb.GetFile("http://server/sites/site/library/folder/file");
}
}

File properties are available through its Item property. If you have for example a text field in the document library called "My Custom String Property", and you want to know the value for that field in a specific file, use the following code:

using(SPSite mySite = new SPSite("http://server/sites/site"))
{
using(SPWeb myWeb = mySite.OpenWeb())
{
SPFile file = myWeb.GetFile("http://server/sites/site/library/folder/file");
string filePropertyValue = file.Item["My Custom String Property"].ToString();
}
}

We now want to add a new item to a list:

using(SPSite mySite = new SPSite("http://server/sites/site"))
{
using(SPWeb myWeb = mySite.OpenWeb())
{
SPList contactsList = myWeb.Lists["Contacts"];
SPListItem newItem = contactsList.Items.Add();
newItem["First Name"] = "Ishai";
newItem["Last Name"] = "Sagi";
newItem.Update();
}
}

Lets change all items in the list to build the email address based on the first and last name (in the format of 'first.last@testing.com') :

using(SPSite mySite = new SPSite("http://server/sites/site"))
{
using(SPWeb myWeb = mySite.OpenWeb())
{
SPList contactsList = myWeb.Lists["Contacts"];
foreach(SPListItem existingItem in contactsList.Items)
{
existingItem["E-mail Address"] = existingItem["First Name"] + "." + existingItem["Last Name"] + "@testing.com";
newItem.Update();
}
}
}

Well, that's it. If you think of more snippets like that, let me know!

[Update 4/4/2007 : I have replaced the old samples to best practice format (using using)]

Monday, August 28, 2006

MOSS 2007 Beta2 bug - Profile Database Property's Choicelist Cannot Be Updated By Code

I spent a long time trying to figure out what I was doing wrong before giving up and reporting this, just to get a reply that MS knows about the problem and are working on a fix!!!
And here I was using reflector trying to see how MS did that in their controls.

The problem is when you are using the portal object model to change a property in the profiles database.
For example, I was trying to add, update or remove values from a choice list in a property. I had a property called "Location", and I wanted to create an automated application that will update the choices the user can choose from.

After a quick search in the SDK, I wrote the code I needed to run:

using (SPSite site = new SPSite("http://servername"))
            {
                   ServerContext context = 
                       ServerContext.GetContext(site);
                   UserProfileManager m_mngr = new UserProfileManager(context);

                   //Get the properties
                   PropertyCollection props = m_mngr.Properties;
                   Property location = props["Location"];
                   property.ChoiceList.Add("Sydney");
                   property.Commit();
               }
            }

If I ran it in a web application (web part) or a console application, and then immediately requery the choice list, it appears to work, but then if you clear the application cache, or if you just go to the administration page for the property you can see the values were not updated.

The real depressing bit is that I really need this to work, since my project needs to go live in a month, and if Microsoft doesn't fix that in the Beta 2 Refresh, I don't know what I will do!

Sunday, August 27, 2006

Is google trying to kill sharepoint?

According to an article in newsome, google is planning to release tomorrow a package with "web site creation applications".
The article doesn't elaborate on this feature, but it does contain a quote from Tom Rizzo (director for Office SharePoint Server at Microsoft) who shrugs off google as a competitor.
So I guess while SharePoint will remain uncontested in the corporate portals (for me at least), I will definitely have a look at this mysterious "web site creation applications". I have been wanting to move from blogspot for a while now.

By the way, I just ran a spell check on this post, and guess which names were not recognized?
Google, blogspot and sharepoint!
why am I surprised? Because this site is blogspot, so it should recognize its own name, and its owned by Google, so why not include the land lord in your spell checking?
Its exactly like MS Word not recognizing SharePoint or PowerPoint (here is another word it didnt recognize).

Tuesday, August 22, 2006

Cool - override default list template (with contents) size limit! (MOSS 2007)

Meron Fridman just published a great tip on how to override the default 10mb limit when saving a list template. Good job Meron!

Sharepoint training answers

To those of you who asked, the training session I mentioned a couple of days ago is not something you can register to, as I usualy get contracted to do these things for organizations who want to train their in-house developers. However, if there are people in Australia who want that kind of training - drop me a message in this blog (dont forget a phone number or email!) and I will contact you and we can have a chat!

Monday, August 21, 2006

Reasons why not to buy the O2 Atom

Ok, I know this is a sharepoint blog, but I am too pissed off right now to care! I bought an O2 Atom mobile phone when it first came out (around February) and am VERY dissapointed with it!

Let me just say before my rant that I did install the latest RAM and all updates available from O2 (I even made sure of that by calling their tech support).

Whats wrong? everything:

  1. The machine is just slow!
  2. answering calls more often then not disconnects the call.
  3. Skype is not supported, and while the application runs, people on the other side cannot hear me (even though I can hear them). I researched this on the internet and found that this is common to Atom users (while iMate users dont have the problem). O2 say that skype is 3rd party and not their responsibility, while skype says they only support specific manufacturers (such as iMate)
  4. The phone design isnt protecting the battery. its very easy for the battery cover to slide out. I had to buy a special case for the phone to prevent that.
  5. Since I got it, the phone would periodically shut itself down without explanation. sometimes when answering a call, sometimes when receiving an SMS and sometime just when in my pocket
  6. I sent the phone to be fixed in O2. I thought it was nice of them that I didnt have to pay for delivery. however, once I sent it, I got no confirmation that the got the phone. I called support after 3 weeks and they told me it arrived, but no one could tell me whats up with it. A day later (after they didnt call me back as promised) I called them again and was told the motherboard needs to be replaced. again, no time was specified. A day later (AGAIN - after they didnt call me back as promised) they told me they cant get in touch with the store that does the repairs, and they will call me back Three days later (need I say they didnt call me, even though I asked to talk to a manger) I called them and was told a manager actuall contacted the store and the phone will be ready in two weeks (this is after a month has passed and me with no phone!). So a month and a half seems reasonable to these people to fix a phone that is under warranty???

Sorry O2, I will not be a future customer, and I will warn my friends to avoid you. You are lacking both in customer service as well as product quality.

MOSS 2007 4 day development training

I was busy all last week delivering my first MOSS2007 developer training. It was really interesting going over my regular SharePoint 2003 course programme and then modifying it to fit the new technology.

Sadly, the new technology is too much to deliver in such a short period of time, especialy when your developers have to start developing sharepoint applications this week!

Thats why I had to cut down on some of the new stuff, and concentrate on basic sharepoint functionality, while leaving the new stuff for the future. Now, I am not a big fan of powerpoint presentations, and I prefer to run workshops - allowing my students to actually do what they they are learning about. whats the point of showing a presentation about lists if they dont get to actually build a list and configure it?

Here is the agenda I built for the course:

Day 1 – Leveraging SharePoint’s Built-In Power

09:00 – 10:20
Presentation

How the SharePoint platform works (IIS, SQL and ASP.NET2)

10:20 – 10:30
Break

10:30 – 12:00
Presentation
Built-in SharePoint Features: Sites, Lists and Columns, templates and web parts.

12:00 – 13:00
Lunch

13:30 – 14:30
Hands-On Lab
Training Exercise: Creating a SharePoint site in IIS. Using out-of-the-box site templates and lists. Student challange Create a customer list of devisions in the student's organization with metadata on each devision. Create a list of departments in the organization, and add meta-data on every department. add a lookup to the devision list, so that each department is linked to one devision.

Create views for the lists filtering and sorting and grouping the lists differently.

14:30 – 14:50
Hands-On Lab
Create a custom list template using “save as template” and reuse the template to create new lists.

14:50 – 15:00
Break

15:00 – 16:30
Hands-On Lab
Using the Built-in Web Parts:

  1. The “List Viewer” web part
  2. The “Content Editor” web part
  3. The “Query String Filter” web part
  4. The “RSS viewer” web part
  5. The “Page viewer” web part
  6. The “Search” web parts

16:30 – 17:00 Hands-On Lab Create a site template using “save as template” and reuse the template to create new sites.

Day 2 – Customising SharePoint

09:00 – 10:20
Presentation
SharePoint Object Model (OM) - usage of console applications to access sharepoint lists.

10:20 – 10:30
Break

10:30 – 11:30
Hands-On Lab

Create a console application to connect to the lists and query them using SPSite, SPWeb and SPList objects. Use SPView to see how CAML is used by the views of the lists.

11:30 – 12:30
Presentation

Developing SharePoint Web Parts Using ASP.NET2

12:30 – 13:30
Lunch

13:30 – 14:00
Hands-On Lab

Exercise – My First Web Part™ Create a web part showing "hello world" using html rendering. Deploy the web part.

14:00 – 14:10
Break

14:10 – 15:00
Presentation

Web part controls - using server side controls in a web part. The correct use of "CreateChildControls" and the web part life cycle.

15:00 – 17:00
Hands-On Lab

Exercise – Building a web part that displays lists information utilising both OM and CAML, using server side controls. Make the title of the list items a link to the properties of the list items using the "Forms" collection of the SPList object. Learn the difference between "Title", "LinkTitle" and "LinkTitleNoMenu".

Day 3 – Advanced SharePoint Programming

09:00 – 10:20
Presentation

Developing SharePoint Event Handlers

10:20 – 10:30
Break

10:30 – 12:30
Hands-On Lab

Develop a list event handler and a site event handler, deploy using features and using a deployment application.

12:30 – 13:30
Lunch

13:30 – 14:50
Presentation
Connectable web parts

14:50 – 15:00
Break

15:00 – 17:00
Hands-On Lab

Build two web parts – supplier and receiver

Day 4 – InfoPath 101 & Implementing Our New Skills

09:00 – 10:00 Presentation
Introduction to InfoPath.

10:00 – 10:10
Break

10:10 – 12:30
Hands-On Lab
Using InfoPath to create a form. The form connects to the 2 sharepoint lists (division and department) to create a master-detail connection. The form submits information to a sharepoint library.

12:30 – 13:30
Lunch

13:30 – 15:00
Presentation
Site columns, Content types and custom fields

15:00 – 17:00
Hands-On Lab
Create Site columns, Content types and custom fields.

Future Training Plans

  1. Workflow development
  2. Excel Services
  3. Business Data Catalogue
  4. Single Sign On

Thursday, August 10, 2006

Free WSSv3 web part...soon

A few weeks ago I promissed I would release a code sample, but since then I didnt have time to finish the sample. I will make an extra effort to finish this code. As for what this is about - I have created two web parts to make use of site properties. This is an under-used feature in the object model of sharepoint - adding string properties to a site. The reason its underused - there is no user interface to use it! so why not make one? A possible scenario is when you want to save additional metadata on a site. storing this metadata within the SPWeb object will help reduce runtime for applications that in the past saved the metadata elsewhere (for example in lists, text files or external databases). A good example from the past - we had a project where the customer wanted a WSS site for each project that he had in project server, but to be used for it own purposes. We had to find a place to store the ID of the project and the URL of the project server for each site. This kind of solution over complicates a design for something that should have been rather simple. Another hipothetical example : using sites as objects. Lets say a site represents a book cabinet, and the lists in the site listed the books in the cabinet. people would go into the site and add or remove books from the list, or change the status of the books. Cabinets were identified by the site's name and description. Now - what if we want more information about the cabinet?
  1. its location
  2. its height
  3. its width
  4. its color

and now we want a web part that shows us all the sites in a list so people can filter and see "only the black cabinets" (for example). We also want to make sure that when people create a new "cabinet" they will fill in the details for the cabinet.

There were ways to achive that, but again having properties on the SPWeb object simplifies things.

The only thing missing now is a way to implement these properties. My proposed two web parts will fill that void.

The first web part will display the site's properties (based on a set of rules) The secont web part will allow users to edit the site properties (again, based on a set of rules)

So as I said, the web parts are almost complete. I will probably feel comfortable enough to upload the one that displays properties sooner, as I am having problems with the editing one - I am trying to utilize some cool controls to allow editing different types of properties (even though all the properties are string properties).

Keep in touch - comming soon!

Wednesday, August 09, 2006

User Profile Event handling?

I was researching into user profiles, as one of my objectives is to get any change a user does to his profile and then act on the change - copying the values to other systems in the network.

Since we need the replication to be immidiate and we cannot rely on a scheduled job like MIIS or other solutions, I could only think of two ways to achive it:

  1. Redevelop the "EditProfile.aspx" page, and override the form submit so it is handled by my code.
  2. Find a way to hook into the "profile changed" event.

Now, the first option is an ugly business. I would prefer not to mess around rewriting code that Microsoft was kind enough to supply me with! The EditProfile page is complex enough with the new choice fields, and person fields for me and with the access-security functions, I really dont want to change it unless I find no other way.

The second option is my favorite one - write an event handler and listen for profile changes.

Angus Logan from Microsoft told me to take a look at the MSDN article "User Profiles and Audience Targeting Overview" which says in the end "SharePoint Server 2007 also offers an eventing model to track deletions and other actions on the user profiles." This sounds GREAT! exactly what I need, right?

Well - I looked and looked and found absolutly no other referance to this "eventing model". The only thing I managed to find after looking in the object model is an enumeration class "SPAuditEventType" that includes a value of "ProfileChange" . There is no documentation how to use it, and I am still looking into it. Any suggestions?

Tuesday, August 01, 2006

Bad news - synchronous list events bug (or missing feature)

UPDATE:

I have had a chance to look into this again now, and found that indeed it is possible to access and change properties in ItemAdding, if you are doing it through the "AfterProperties" hash table of the event, and not through the list item.
Some things to note:
During ItemAdding, there is no SPListItem object to refer to. It is null in the event properties, because to get an SPListItem a record for the item should be in the database, and during ItemAdding nothing has been written to the database yet.
After ItemAdding, the item is added to the database. When it is added, the values from the AfterProperties are applied to it. If you try to add a property to that hashtable that doesnt exist in the list definition, the user will get an error that the field isn't installed correctly. You may encounter this if you don't use the internal name of the field when you set the AfterProperties.
The moral of the story - Use the AfterProperties in ItemAdding, and when you use it to get or set a field, make sure you use the field's internal name.
That said, my argument with Sahil (see below in the original post) remains - you cannot use the SPListItem, because one cannot exist. His sample code modifies the item that was added before the current item, and not the current one.

Here is a sample code that modifies one of the fields in the ItemAdding event. In this example we have a links list, with a custom column called "Tool Tip" (internal name is "Tool_0x0020_Tip") and we want to set it automatically to the title of the link the user picked:

public override void ItemAdding(SPItemEventProperties properties)

        {

            string toolTipFieldInternalName = "";

            using (SPWeb web = properties.OpenWeb())

            {

                toolTipFieldInternalName = web.Lists[properties.ListId].Fields[TOOL_TIP_FIELD_NAME].InternalName;

 

            }

 

            string urlVal = properties.AfterProperties["URL"].ToString();

            SPFieldUrlValue val = new SPFieldUrlValue(urlVal);

            string desc = val.Description;

            properties.AfterProperties[toolTipFieldInternalName] = desc;

        }

Original post: (was posted during Beta2)

I have been trying to create an event handler that checks the item's properties before it is saved. This is supposed to be easy in MOSS - just create an event handler, override the "ItemAdding" event and check the properties of the list item. right?

Wrong.

Apperantly, the SPItemEventProperties object that is received in the ItemAdding event is totaly useless! The "ListItem" is null, the ListItemID is null, the AfterProperties and the BeforeProperties are both empty so basically we have no idea what the user typed - we have no way to control it!

Searching the internet I found that Sahil wrote a terrific article on creating an event handler (with really good funny writing and good guidlines) in which he tried to implement a workaround to the problem.

Unfortunately, I tested his code and it seems something is missing. I think he meant to use the ItemAdded event or something (or maybe not, since his scenario demands using the ItemAdding event).

Basically he is trying to get the item from the list by getting the last item int the list. But he didnt notice that the item doesnt exist yet, so his code is quering an existing item instead of the new one about to be added - he is always checking the last item in the list, but not the one the event is triggered for. So to sumarrize - I found no way currently to get the list item details before it is added to the list (then you can use the "ItemAdded" event). I have contacted Microsoft and waiting for their reply.

If you are using Sahil's article (which is quite good except for the above), look out for embedding the list's URL in the code. Sahil probably meant to write about it, but he focused on the demo.

The more elegant way to get to the list is:

Shail's original code SPList SahilSurvey = properties.OpenWeb().GetList("http://homepc/Lists/Sahil");

My proposed change: SPList SahilSurvey = properties.OpenWeb().Lists[properties.ListId];

You will notice that in my solution you dont have to hard code the list URL, and that way you make the event handler generic- able to handle all lists instead of just the one under "http://homepc/Lists/Sahil".

Tuesday, July 25, 2006

New stuff in web parts for sharepoint developers

Some of you may be wondering why I have not posted in a couple of days. Well, there was the weekend, and then I started working on a set of two web parts that I want to publish here. I will keep them as a surprise, but I promise they will be open source if you promise not to send it to the http://thedailywtf.com!

Meanwhile, I will tell you about a couple of things I discovered while working on these web parts:

  1. I wanted to create two web parts in one DLL. This seems to be an easy task - exactly like making one web part - just add another class, inherit from "webpart" and make sure its has the same namespace and make sure that you register it as safe. Sounds easy right? Well - I managed to waste two days trying to make this work (and this should go to http://thedailywtf.com) because I didnt notice that the second class I added didnt have the "public" declaration (this is the default for a new class in visual studio). So I tried and tried and tried, and finally the good MVP Daniel Larson helped me find the small mistake.
  2. This is something new for developers - fields in lists now have new properties in the object model :
    1. ShowInDisplayForm
    2. ShowInEditForm
    3. ShowInListSettings
    4. ShowInNewForm
    5. ShowInVersionHistory
    6. ShowInViewForms
    I can see we are going to have so much fun with these properties! So many people who want today to show fields in the version history screen will be delighted to know this, as well as people who want to edit the forms but are reluctant to use frontpage (and with reason!) To bad these properties are only accessible through code. Adding these to the UI would have been great! I have not had the time as yet to actually use them (I just noticed them in passing) but I do hope they work like they sound (the msdn has "todo" in the documentation of these features)
  3. While we are at it - another nice addition to the field object "GetFieldValueForEdit". I dont know yet what it does, but I have my suspicions!
  4. Ahhh, this is a great one- "FieldRenderingControl". Again, no documentation and I had no time, but I think this is going to be a huge time saver for all of us developers who need sometimes to write alternative input forms for lists. Just think about it - the field contains the information of which control to use. I will have to check tomorrow how it works exactly with the default field types since it returns a "sharepoint webcontrol" and not a regular "web.ui control". I will update. (save me some time if you know - post a comment!)

So now you know that my secret web part has something to do with fields...I wont tell you ny more so I wont ruin the surprise!

Wednesday, July 19, 2006

Great new search solution for WSS 2

I know I usually write about wss3 and sharepoint 2007, but this product just got released by KwizCom that I thought all my readers should be aware of.

The product is "WSS Cross Site Search" and it allows you to search in WSS as if you had portal (across sites, advanced search and more) and for cheap (current pricing stands on 560$)!

Now, I have seen some other products that do similar items, but what I liked about this one, is that it completely integrates into the wss framework. Take a look:

And check out the advanced search page:

I also like the sound of some of the items in the feature list:
  • Easy management of properties available for the advanced search
  • User can define that the search results page will be displayed on a new window
  • Clicking an Office 2003 document (Word, Excel, PPT) in the search results page opens it in Edit mode
  • Available both as a web part and as a custom control, enabling easy deployment both in WSS sites and WSS site definitions

How good is that???

I hope you find it as useful as I do. The guys from KwizCom did it again.

Link to the product page

kick it on SharePointKicks.com

Monday, July 17, 2006

Modifying the WSS3 tree navigation control

I wanted to create a structure of sites and allow easy navigation between them. Sharepoint 2007 (or rather, WSS3) has a fantastic tree view of the site hierarchy that you can activate if you want through the site administration page.

One of the grate things about the tree view is that it expands on the server side. This means that the page wont suffer from bad performance even if the site tree is large (unless there are a lot of sites directly underneath it and not in a hierarchy).

I will explain in this article how to tweak some features of this control.

Step 1 - Turn on the tree-view navigation:

  1. Open the site you want to display the tree in
  2. Open the "site actions" dropdown and select site settings
  3. From the site actions, under "Look and Feel" click "Navigation Options"
  4. Tick the "Enable Tree View" box to show the tree view. Notice that you also have an option to disable quick launch, but that is for another article.
  5. Go back to the home page in your site:

So far, so good.

Now - my problem was that I wanted the users to see only the sites and not the document libraries. As you can see - the tree view by default is showing everything (my sites were blank sites so they didnt have any lists, but I want them to have lists and not to display them) including the "Form Templates" library in the top level site!

Step 2 - Modify the Control in the Master Page

  1. Open the site in frontpage.
  2. In the folder list, expand the "_catalogs" folder and then the "masterpage" folder and find the "default.master" page and open it.
  3. I prefer to work in split view - that way I can get to where I want in the code much faster. Just click on the tree control in the bottom pane, and the code pane at the top will jump to the code section of the tree.
  4. Find the piece of code that says ">SharePoint:sphierarchydatasourcecontrol<" as shown below:
  5. Modify the code- under "IncludeDiscussionFolders" add a new line and write (frontpage offers intellisense so it will help you write it) the code that says not to show document libraries, lists and folders:
  6. Save the file and exit sharepoint designer.

End Result

You can see that now the navigation shows a tree of only sites. You also learned how to show only document libraries, or only lists and so on. (note - there is a way to tell it not to show sub webs...can you figure it out yourself?)

Hope you enjoyed this. More to come!

if you liked this tip, help it by kicking it!
kick it on SharePointKicks.com

[Update: 27/04/2007]
I have been asked by people "why can we not see the treeview after enabling it". Well, the answer is simple - the tree view control isn't in the master page for the page you are looking at. You will need to either change the master page itself, or set a different master page for the page.

What Video Game Character am I?

At the risk of being accused that I have too much time on my hands, I will post the result of this short personality test I just did, and found out that if I was a Video Game Charecter I would be....:

What Video Game Character Are You? I am a Gauntlet Adventurer.A Gauntlet Adventurer.

I strive to improve my living conditions by hoarding gold, food, and sometimes keys and potions. I love adventure, fighting, and particularly winning - especially when there's a prize at stake. I occasionally get lost inside buildings and can't find the exit. I need food badly. What Video Game Character Are You?

I think this describes me pretty well.