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".