I ran into a problem recently where I was attempting to update the permissions on an SPListItem within code but ran into the following error:

Updates are currently disallowed on GET requests. To allow updates on a GET, set the ‘AllowUnsafeUpdates’ property on SPWeb.

Now I’m quite familiar with this error, and it’s one of the few errors in SharePoint that gives you a hint in terms of what you need to do: set the AllowUnsafeUpdates property to true on your SPWeb object.

Well, I did that, but without success. I was still receiving this error. I did a bit of digging and came across some useful information on Hristo Pavlov’s blog. His article is titled What You Need To Know About AllowUnsafeUpdates (Part 1) and is a must read for anyone working with these objects.

The root of my issue turned out to be that my AllowUnsafeUpdates property was being reset to false, even after I had already set it to true:

When any object that implements ISecurable (those are SPWeb, SPList and SPListItem) breaks or reverts their role definition inheritance. This means every time you call SPRoleDefinitionCollection.BreakInheritance(), BreakRoleInheritance(), ResetRoleInheritance() or set the value of HasUniquePerm the AllowUnsafeUpdates property of the parent web will reset to its default value and you may need to set it back to true in order to do further updates to the same objects.

To resolve my issue, I had to reset the AllowUnsafeUpdates property to true after executing BreakRoleInheritance() in my code. I encourge you to read the rest of Hristo’s blog as it really helped me understand this property a little better.

Tagged with:  

Within a SharePoint list or library, you have the ability to add columns that are of type Multiple Lines of Text. Within the settings of this column, you are able to select whether or not you’d like to Append Changes to Existing Text. If you’re unsure, this setting is located in the Additional Column Settings section when you create or edit an existing column.

Now if you select Yes, and click OK, unless you have versioning turned on for the list, you will receive the following error:

You must first turn on versioning in this list before adding or creating columns which append changes to existing text.

So it seems as though versioning is an absolute requirement for this setting. I did a bit of testing and wanted to record my observations:

  1. If you turn on versioning for the list and set this setting to Yes, all that SharePoint will really do is display the ‘updates’ to this field in the edit and display forms. There’s nothing else funky going on behind the scenes. Hence the need to have versioning turned on first; all updates are actually managed through versioning. This setting just lets us see into the versions within the edit and display forms.
  2. Changing this setting back to No after you have already made several updates will NOT result in a loss of data. It will simply mean that SharePoint no longer displays the ‘updates’ in your edit and display forms. To verify if this is true, simply check the versions of the item and you’ll see that your edits for that particular field are still there. This is really easy to test and I encourage you to do so.

If you’ve selected Yes, the key thing to note is that SharePoint will store blank entries in the Version History of that item. If this option is set to No, SharePoint will still record any updates to the field as versions of the item, but it won’t store any blank entries. This is an important consideration if you’re building any custom forms or views for this data and are worried about blank entries showing up.

If you’re a developer, you may want to consider not using this option and if you need to show the ‘updates’ to a column in your edit and display forms, then write it yourself by looping through the versions of a listitem (a topic for another blog post).

If you’re working in SharePoint Designer and you’re wondering why your Multiple Lines of Text column is not displaying correctly, try replacing:

1
<xsl:value-of select="@Updates" disable-output-escaping="yes" />

with

1
<SharePoint:AppendOnlyHistory runat="server" FieldName="Updates" ControlMode="Display" ItemId="{@ID}"/>

I just want to point out that attempting to set the DisplaySize property had no affect. If anyone was able to successfully configure this, please let me know.

That’s really all I wanted to say on this topic. I just wanted to clarify a few things I had noticed. I hope that makes sense to everyone. Ping me if you have any questions.

Tagged with:  

To my knowledge (and someone please post and correct me if I’m wrong) there doesn’t seem to be a solid way to build an SPQuery object that can return distinct values from a list. I’ve seen some clever tricks for getting around this particular problem, but nothing quite like this.

If you dig through this post a little bit, you’ll find the technique to getting distinct values comes down to leveraging a DataView.ToTable() method to return only distinct results.

So let’s break this down a bit. A typical scenario for me is to build a data table that contains all of my data (via an SPQuery to the list), set the data source of my control to that data table and then bind.

(In my case, I work specifically with the Telerik RadGrid and the Telerik RadComboBox but the same idea applies to the standard ASP.NET controls)

1
2
3
4
5
DataTable groupedDataTable = originalDataTable.DefaultView.ToTable(true, "Title")
 
dataGrid.DataSource = groupedDataTable;
 
dataGrid.DataBind();

The ToTable() method accepts two parameters as demonstrated above.

  1. bool distinct simply indicates whether or not to supply distinct values
  2. params string[] columnNames is a string array that contains a list of the column names in the orignal data table that you’d like to be returned
This worked quite nicely for me, a huge thank you to the original author of the referenced post.
Tagged with:  

New SmartTools Release for SharePoint

On January 22, 2009, in SharePoint 2007, by shereen

Jan Tielens recently released a new version of the SmartTools that’s worth checking out. The TableRow highlight and jQuery additions in general are pretty exciting.

http://weblogs.asp.net/jan/archive/2009/01/22/new-release-of-the-smarttools-for-sharepoint-project.aspx

Tagged with:  

You might run into a scenario on your SharePoint development box where the WSS_Content_log file grows to be quite large. If you’re limited on hard drive space and need to know how to truncate and shrink this log file, follow the directions below. For my particular installation, I had WSS 3.0 and SSEE installed with all the defaults.

Before we begin, you may want to take a bit of time to learn about Recovery Models, Truncating and Shrinking.

  1. Let’s start. Open Microsoft SQL Server Management Studio Express. If you don’t have that tool installed, you can get it free from Microsoft. Expand Databases. Right click on the WSS_Content database, go to Properties, Options, and change Recovery model: to Simple. Click OK.
  2. Click New Query. Once the blank page opens up, make sure the WSS_Content database is selected.
  3. Run the following command first. This will truncate the log file. We must do this step first before we can shrink the file.

    1
    
    BACKUP LOG WSS_Content WITH TRUNCATE_ONLY
  4. The next step will actually shrink the log file and recover our disk space. You can use the command below to confirm the name of the file we’ll be shrinking.

    1
    
    SELECT * FROM sys.sysfiles
  5. The name column will give us the information for the last command – the name of the log file itself. In this case, it’s WSS_Content_log:

    1
    
    DBCC SHRINKFILE(WSS_Content_log, 1)

That should do it. I had a 4 gig content db and a 26 gig log file. All of the above took about 5 minutes or so.

Tagged with:  

How to Find the Server Control ID of a RadGrid

On January 16, 2009, in ASP.NET, Telerik, by shereen

Let’s say you have 2 RadGrids defined in your aspx page. Both grids happen to share the same ItemDataBound event, but you’d like to apply a small tweak depending on what grid is calling the ItemDataBound method.

In order to implement your tweak, you’ll need a way to find the ID of the grid that made the call. And not the ASP.NET generated ID, since that can be rather ugly, but the ID of the control you created in the aspx page. The following example demonstrates how this can be achieved:

1
2
3
<radG:RadGrid ID="rgThisYearsItems" runat="server" OnItemDataBound="rgItems_ItemDataBound"></radG:RadGrid>
 
<radG:RadGrid ID="rgLastYearsItems" runat="server" OnItemDataBound="rgItems_ItemDataBound"></radG:RadGrid>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
protected void rgItems_ItemDataBound(object sender, GridItemEventArgs e)
{
        // we need to determine what grid is calling the itemdatabound event
        RadGrid grid = (RadGrid)e.Item.OwnerTableView.OwnerGrid;
 
        if (grid.ID == "rgThisYearsItems")
        {
            // perform some logic here
        }
 
        if (grid.ID == "rgLastYearsItems")
        {
            // perform some logic here
        }
}

The reason you might want to implement the above is for code reuse. If you’ve got two grids and the ItemDataBound event for both will be really similar minus a line or two, you can have them both call the same ItemDataBound event and use the above logic to determine when to run the custom pieces.

Thoughts?

Tagged with:  

So here’s the idea. I’ve got a RadGrid on my page that is populated programmatically. I build a DataTable from various different sources and once I’m satisifed with how my DataTable looks, I set the grid’s DataSource property and bind.

That’s all good, except now I want to insert a header row in the middle of my grid. The idea behind this row is to simply provide a clear segregation between my different sources of data. It’s all one grid remember, but I wanted a way to distinguish between the data.

I came up with the idea to simply add a header row at the point I needed, set the ColumnSpan to match the number of columns I have in my grid, set the HorizontalSpan to center the text and finally set the Visibility on all other columns to false.

Here is what I ended up with. The grid is setup with 5 columns: Name, Address, City, Province and Country. At the point where I’d like my see my header row in the grid, I set the Name column to the text I’d like the header to contain. Keep in mind that I have rows being added before and after the code sample below. I’ve inserted the code exactly where I want my header to appear:

1
2
3
DataRow row = dt.NewRow();
row["Name"] = "My heading that I'd like to show";
dt.Rows.Add(row);

Now in the ItemDataBound event, I can modify this particular row that I just created so that it spans all the columns and is centered as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
protected void RadGrid1_ItemDataBound(object sender, GridItemEventArgs e)
{
    if (e.Item is GridDataItem) 
    {
        GridDataItem dataItem = e.Item as GridDataItem;
 
        // i use the second index to get at the name column. the first two indexes
        // are empty for me and don't contain any valuable data
        if (dataItem.Cells[2].Text == "My heading that I'd like to show")
        {
            dataItem["Name"].ColumnSpan = 8;
            dataItem["Name"].HorizontalAlign = HorizontalAlign.Center;
 
            dataItem["Name"].BackColor = System.Drawing.Color.Black;
            dataItem["Name"].ForeColor = System.Drawing.Color.White;
 
            dataItem["Address"].Visible = false;
            dataItem["City"].Visible = false;
            dataItem["Province"].Visible = false;
            dataItem["Country"].Visible = false;
       }
    }
}

That’s what I came up with and it seems to work great. If anyone has a better technique for implementing this, please let me know.

Tagged with:  

This article will talk specifically about how to add a Rich Text Editor to your custom application pages. When initially doing some research on this topic, I found a lot of information, but not anything useful that I could actually implement. Here are my steps for adding a control of this type to your pages:

  1. If you would like to leverage the default sharepoint rich text editor control within your own custom pages, there’s one class you need to get familiar with: InputFormTextBox
  2. The actual MSDN reference is not very helpful so to get started with a control of this type, you’ll need to know a couple things. Let’s begin by adding the control to our page as follows: 
    1
    2
    
    <wssawc:InputFormTextBox ID="iftxtDescription" runat="server" TextMode="MultiLine" Rows="20"
    RichTextMode="FullHtml" RichText="true"></wssawc:InputFormTextBox>
  3. The reason I know it’s wssawc is because at the top of the custom application page, Microsoft.SharePoint.WebControls namespace should be registered with a tagprefix of wssawc
    1
    
    <%@ Register TagPrefix="wssawc" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
  4. Some properties to be aware of:
    • ID – all controls need this. You’ll use the ID to work with the control in the code behind or the inline code
    • TextMode – this specifies whether the control is a Password control, a MultiLine control or SingleLine control. If you’re attempting to create a rich text editor, you’ll want to set this to MultiLine.
    • Rows – specifies the rows/height of this control
    • RichTextMode – specifies whether the mode for the rich text. Options are: Compatible, FullHtml, HtmlAsXml.
    • RichText – true or false. Don’t forget to set this to true!
  5. To save data from this type of control:
    calendarListItem["Job Description"] = iftxtDescription.Text;
  6. To read data from a rich text column into this control:
    1
    2
    
    SPFieldMultiLineText multiDescription = (SPFieldMultiLineText)listItem.Fields["Job Description"];
    iftxtDescription.Text = multiDescription.GetFieldValueForEdit(listItem["Job Description"]);

That should do it! I should point out that the multiDescription object that we created above actually has a couple useful methods beyond the one that I used. GetFieldValueForEdit() will grab the contents of the field in rich text and display it in my control quite nicely. I could also have used GetFieldValueAsHTML() for html or GetFieldValueAsText() for plain text.

Note: If you attempt to set the Enabled or ReadOnly properties of this control, they won’t work. I ran into this issue myself and confirmed it with several other users having the same problem. Microsoft has acknowledged this as a bug (37846) but I have yet to find any documentation on this bug. If you do find anything, please let me know!

Tagged with:  

If you’ve ever worked with SharePoint columns that are of type Lookup and you’re reading this data in via the object model, you’re probably already aware that the value gets returned as an ugly string in the form of:

FIELDLOOKUPID;#FIELDVALUE (23;#Vancouver)

What you want to avoid is using string manipulations to get at the ID or Value of that lookup. An example of a poor practice would be:

1
2
string city = Convert.ToString(listItem["City"]);
city = city.Substring(city.IndexOf("#") + 1);

If you output the variable city, you’ll find it now contains Vancouver.

There is a better way to do this. The SharePoint object model actually contains some useful helpers for dealing with column types that return this format:

SPFieldLookupValue

This class is very useful when working with columns that are of type Lookup. The syntax for using this is pretty straight forward. Given our example above where we have a column named City that is a lookup into the Cities list, here is what our code would look like:

1
SPFieldLookupValue cityLookup = new SPFieldLookupValue(Convert.ToString(listItem["City"]);

To access either the ID or the Value of that entry, we use:

1
2
string cityID = cityLookup.LookupId;
string cityName = cityLookup.LookupValue;

Now what’s really handy about the above two strings I’ve created is that the cityID string now contains the ID of the city that’s referenced in the Cities list.

I’ve talked about reading values from a column of type Lookup, the next article in this series will talk about how to save values to a column of this type. Keep in mind that the SPFieldLookupValue class is just one of many for this type of operation. If you’re working with Hyperlink column types, as an example, you’ll want to check out the SPFieldUrlValue class.

Tagged with:  

Vancouver SharePoint User Group

On January 7, 2009, in SharePoint 2007, by shereen

If anyone living in the Vancouver, BC area, you might want to check out the Vancouver SharePoint User Group.

Their next event is on January 13, 2009.

Tagged with: