Sharepoint Tips And Tricks is Ishai Sagi's sharepoint information blog. It specializes in Microsoft SharePoint technologies, including web parts, development, configuration, customization, and best practices for the use of Microsoft SharePoint Server and Windows SharePoint Services. It also provides some related Office Information, including VSTO and VSTA and other office application development tips.
Thursday, August 31, 2006
My first WTF story published
read about my sad experience in WTF-U.
CAML builder for 2007 was 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?
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)
Sharepoint training answers
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:
- The machine is just slow!
- answering calls more often then not disconnects the call.
- 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)
- 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.
- 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
- 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:
- The “List Viewer” web part
- The “Content Editor” web part
- The “Query String Filter” web part
- The “RSS viewer” web part
- The “Page viewer” web part
- 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
- Workflow development
- Excel Services
- Business Data Catalogue
- Single Sign On
Thursday, August 10, 2006
Free WSSv3 web part...soon
- its location
- its height
- its width
- 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:
- Redevelop the "EditProfile.aspx" page, and override the form submit so it is handled by my code.
- 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)
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;
}
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".