May
8
2013

SharePoint 2010: Indexed columns and changing the locale setting

It's a well known issue that if you change the regional setting of a site collection with indexed columns an error is raised:

The column "column1" in the list or library "list1" has been marked for indexing. Please turn off all indexed columns before changing the collation of this site. You may re-index those columns after the collation of the site has been changed.

This alone is nothing special, but if you change the locale using PowerShell or ServerCode (see examples below), everything works fine without any errors.

$culture = [System.Globalization.CultureInfo]::CreateSpecificCulture(“sv-SE”)
$spWeb = Get-SPWeb http://someurl
$spWeb.Locale = $culture
$spWeb.Update()
$spWeb.Dispose()

Listing1 - PowerShell

SPContext.Current.Web.Locale = new CultureInfo("sv-SE");
SPContext.Current.Web.Update();

Listing2 - ServerCode

Because I had to change the locale on large site collections with lots of content, i wondered WHY SharePoint behaves like this and started a little research. There are three ways I want to inspect:

  1. The "Regional Settings Page", which is reached by selecting "Regional Settings" in the "Site Settings" area of a site collection.
  2. The "PowerShell Way", as described in Listing1 above.
  3. The "ServerCode Way" as described in Listing2 above.

My first discovery was that way two and three are acting exactly the same:

public void Update()
{
bool flag = this.m_bIsDirty || (this.m_spRegionalSettings != null && this.m_spRegionalSettings.IsDirty);
if (flag)
    {
        this.InitWeb();
        uint lcid = (uint)this.m_lcid;
        this.TraceWebOperation("Update", true);
        uint collationLCID;
        this.Request.SetWebProps([...Many Properties...]);
        this.m_webVersion += 1u;
        this.RegionalSettings.SetCollationLCID(collationLCID);
        this.RegionalSettings.IsDirty = false;
        this.m_bIsDirty = false;
    }
}

Listing3 - SPWeb.Update()

When executing SPWeb.Update(), SharePoint checks if the locale was changed. If yes, SPWeb gets reinited and "RegionalSettings.SetCollationLCID" is called, which does nothing more than this:

internal void SetCollationLCID(uint lcidCollation)
{
    this.m_lcidCollation = lcidCollation;
}

Listing4 - SetCollationLCID

So, what does the first way, the Regional Settings Page? If we take a look at the .aspx Page ("regionalsetng.aspx", located in "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\template\layouts"), we can see that the onClick Event of the "OK" button is bound to "BtnUpdateRegionalSettings_Click". The DLL for SharePoint ApplicationPages is located at "C:\inetpub\wwwroot\wss\VirtualDirectories\<yourwebapp>\_app_bin". Using ILSpy we can see what "BtnUpdateRegionalSettings_Click" does:

bool bIndexed = false;
foreach (SPList sPList in sPWeb.Lists)
{
	if (!sPList.HasExternalDataSource)
	{
		foreach (SPField sPField in sPList.Fields)
		{
			if (sPField.Indexed && (sPField.Type == SPFieldType.Text || sPField.Type == SPFieldType.Choice))
			{
				bIndexed = true;
				try
				{
					SPList sPList2 = this.Web.Lists[sPList.ID];
					if (sPList2.DoesUserHavePermissions(SPBasePermissions.Open))
					{
						strNvpList = sPList.Title;
						strNvpField = sPField.Title;
					}
					break;
				}
				catch
				{
					break;
				}
			}
		}
		if (strNvpField != null)
		{
			break;
		}
	}
}

Listing5 - BtnUpdateRegionalSettings_Click

If the locale setting was changed, a simple foreach is executed which iterates through all fields in all lists in the current web. If a field is indexed and has the type "SPFieldType.Text" or "SPFieldType.Choice" a bool is set to true and the loop leaved. Afterwards an exception is thrown, which leads us to the beginning of this article.

I have to admit, I still dont know WHY SharePoint is acting like this Smile Even though I will try it the "PowerShell Way" and see what happens. If anyone knows the reason for this behaviour, feel free to contact me or comment.

May
3
2013

How To (SharePoint 2010): Put items into recycle bin instead of deleting them

A small difference when coding but a big when a user deletes an item by accident:

listItem.Delete();

Deletes the item directly, without putting it into the recycle bin.

listItem.Recycle();

This puts the item into the recycle bin and returns the guid of the new item inside the bin.

Apr
16
2013

HowTo (SharePoint 2010): Stop background scrolling if modal dialog is openend

To stop the background from beeing scrollable if a modal dialog is opened, call the dialog like this:

function openDialog() {
    var options = {
        url: '/_layouts/VisualWebPartProject1/ModalTest.aspx',
        title: 'Title, Description, and Icon',
        dialogReturnValueCallback: onDialogClose,
        width: 640,
        height: 400
    };

    $("body").attr('style', 'overflow:hidden !important');
    SP.UI.ModalDialog.showModalDialog(options);
}

function onDialogClose() {
    $("body").removeAttr('style');
}

When the "openDialog" method is called, the body will be set to "overflow:hidden". This cuts all content smaller than your webbrowsers window. If the dialog is getting closed, the "onDialogClose" callback is entered and the style property will be removed.

As you may note, the style is set with "!important" tag. This is neccessary because SharePoint sets it the same way in its css files. Dont forget to refer jquery for this example:

<link href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/themes/cupertino/jquery-ui.css" rel="stylesheet" type="text/css"/>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.5/jquery.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/jquery-ui.min.js"></script>
Aug
23
2012

Problem with developing custom timer jobs (code is not updating)

Today I had a weird problem when developing a little custom timer job. My first attempt worked well, but after that every change to the code seem to be ignored by the server. I tried to reset the IIS, manually retracted the solution, copied it to the bin folder and so on… Nothing worked, the code on the central administration was still not the same as in visual studio. After some research I found out that TimerJobs are beeing cached by the SharePoint Timer Service. To delete this cache you have to restart the service. You can do this manually following this way:

Click Start -> Open Run.exe -> type in “Services.msc” -> Select “SharePoint 2010 Timer” and restart it.

This solves your problem – the code is matching again, but it’s very annoying to restart the service everytime you want to debug or deploy something. There’s a little trick to avoid this:

Open Project Properties in Visual Studio -> Insert “net stop sptimerv4″ into the PreBuild Textfield -> Hit return -> Insert “net start sptimerv4″

Now everytime you build your timer projekt visual studio restart the SharePoint Timer Service.

May
2
2012

HowTo: Programmtically add SPFieldMultiLineText field to a list (SharePoint 2010)

Today I struggled when adding a field with the type “SPFieldMultiLineText” to a list.

The trick is at the line where you choose the field type:

someList.Fields.Add("SomeFieldName", SPFieldType.Note, true);

I expected something like “SPFieldType.MultiLineText”. But for some reason you have to choose “Note”. In the comments of the “Note” enum you can read this:

“Specifies a field that can contain multiple lines of text. Corresponds to the SPFieldMultiLineText class and to the Note field type that is specified on the Field element. Value = 3.”

Finally, I’m inserting it this way:

someList = currentWeb.Lists.TryGetList("SomeList");
if (someList != null)
{
    someList.Fields.Add("SomeFieldName", SPFieldType.Note, true);
    var someField = someList.Fields["SomeField"] as SPFieldMultiLineText;
    if (someField != null)
    {
        someField.NumberOfLines = 6;
        someField.Update();
    }

    someList.Update();
}
Apr
27
2012

SharePoint 2010: How to duplicate a publishing page, SPFile, Pages library

It’s near the end of april and I didnt have any special theme to write about  That’s why I give out this snippet:

var pagesList = SPContext.Current.Web.Lists["Pages"];

string destUrl = SPContext.Current.Web.ServerRelativeUrl + _oldPageItem.File.ParentFolder + "/" + _oldPageItem.File.Name;
destUrl = destUrl.Replace(".aspx", "_V2.aspx");
SPContext.Current.Web.AllowUnsafeUpdates = true;

_oldPageItem.File.CheckOut();
var destFile = pagesList.RootFolder.Files.Add(destUrl, _oldPageItem.File.OpenBinary(), true, "Page Duplicator", true);
destFile.Update();
destFile.CheckIn("Page Duplicator");
destFile.Publish("Page Duplicator");
Mar
27
2012

Sharepoint2010: How to detect if and which ribbon button was pressed during postback

Some weeks ago I had the problem that I was not able to detect if the user’s has clicked onto the “Save & Close” button when editing a SharePoint Publishing Page. My workaround was to save the current state on every postback when SPControlMode.Edit was true.

Today I found a much simpler way:

Page.Request.Params.Get("__EVENTARGUMENT");

For example, if I hit “Save & Close” this returns “pagestategroupsaveandstop”. If I click edit I get “edit” and so on. Here I have implemented a simple method to get the state:

public class PostBackArgument
{
    public static string Get(Page page)
    {
        var returnValue = "";
        try
        {
            returnValue = page.Request.Params.Get("__EVENTARGUMENT") ?? "";
        }
        catch (Exception ex)
        {
            //your error handling
        }
        return returnValue;
    }
}

/// <summary>
/// The (currently) needed postback arguments
/// </summary>
public class PostBackArgs
{
    public const string Edit = "edit";
    public const string SaveAndClose = "PageStateGroupSaveAndStop";
    public const string SaveAndContinue = "PageStateGroupSave";
    public const string CheckIn = "PageStateGroupCheckin";
    public const string CheckOut = "PageStateGroupCheckout";
    public const string Publish = "PageStateGroupPublish";
    public const string Undefined = "";
}

I will add a table with more arguments soon.

Mar
19
2012

SharePoint 2010: Safe conflict when updating SPListItem programmtically

Actually I have to implement some kind of an WYSIWYG Editor for SharePoint Pages (SharePoint Publishing Feature). The versioning and “need to checkout file for edit” option are activated. During my test’s I ran into the issue that everytime I changed something on a page and clicked on “Save & Close”, this dialog came up:

First I thougt that it has to do with impersonation, and tried this:

var userToken = SPContext.Current.Site.UserToken;
using (SPSite site = new SPSite(SPContext.Current.Site.Url, userToken))
{
    using (SPWeb authWeb = site.OpenWeb())
    {
        var pageItem = authWeb.Lists["Pages"].GetItemById(1);
        pageItem["MemoryTest"] = TestBox.Text;
        pageItem.SystemUpdate(false);
    }
}

Unfortunately this doesnt change anything, I was still getting the dialog. After this I tried to use SPListItem.SystemUpdate instead of SPListItem.Update:

var page = SPContext.Current.Web.Lists["Pages"].GetItemById(1);
page["MemoryTest"] = TestBox.Text;
page.SystemUpdate();

This was also a failure. The dialog still comes up. I tried many other things, elevated privileges, different way’s of getting the page object (via SPContext, via ID, via OpenWeb) but nothing worked. After hours I found a way. To use SPListItem.SystemUpdate(false) did the trick! If you use SystemUpdate(false) you dont increment the version with your update. This leads to the behaviour that SharePoint don’t recognize that you’ve changed something.

var page = SPContext.Current.Web.Lists["Pages"].GetItemById(1);
page["MemoryTest"] = TestBox.Text;
//false did the trick!
page.SystemUpdate(false);

On the first view this looks a bit dirty, because you change something without affecting the “ModifiedBy” and “LastModified” fields. But in my case the “field to change” is a hidden-field which is never gonna seen by someone. And with the checkout-required flag every version of the page is restorable.

 

Edit:

After a week of testing I found out that I made a general mistake, which leads to the Save-Conflict Dialog:

I instantiated a new instance of the current page object, saved the changed data to it and called the .Update method. This leads to a save conflict because another instance of the page is already instantiated from sharepoint. The solution was quite simple: Use it  To save my data I just have to call this:

SPContext.Current.ListItem["MemoryTest"] = TestBox.Text;

It’s very important that you DONT call update afterwards. This does SharePoint for you when the user hits “Checkin” “Save” and so on.

Mar
14
2012

Maximum number of directive dependencies exceeded

Today during my work on a pagelayout I was stopped by this Exception:

The page ‘/sites/hugo/_controltemplates/blah.ascx’ allows a limit of 11 direct dependencies, and that limit has been exceeded.

After some research I found the (quite simple) solution how to solve this. In the webconfig where this entry:

<safemode maxcontrols="200" callstack="true" directfiledependencies="10" totalfiledependencies="50" allowpageleveltrace="false">
</safemode>

I just had to change the value of “DirecteFileDependencies” from 10 to 20 and everything worked fine again.

Mar
14
2012

Silverlight Exception when creating new SharePoint list

Today I Tried to create a New Custom List via the “normal” backend way: SiteActions -> SiteSettings -> View all Site Content -> Create

This worked pretty well the Last Weeks so i was very surprised when i got this:

Error
An unhandled Exception occured in the Silverlight application.

The Solution was quite simple:
Due to some other Project I had to Turn of the SecurityValidation. After Turning it on again, everything worked fine.

Here is how to activate the SecurityValidation:

  • Open your Central Administration
  • Navigate to "Manage WebApplications"
  • Select your SharePoint WebApp
  • Click on "General Settings"
  • Scroll down to "Security Validation" and set it to "on"

About the author

 

Contact me on:

Linus Winterseel

Month List