If you would like to discuss anything, please contact me via email: Howard.Bayliss@sequence.co.uk

Monday, December 5, 2011

SharePoint Radio Station

We turned SharePoint 2010 into a "Radio Station". Dan Haywood (Microsoft) writes: "This is probably one of the most impressive solutions I have ever seen built on SharePoint 2010"...

My company, Redweb, gives each team the opportunity to work on a Hack Project. We have 33 hours to conceive, build and present an innovative piece of work.

My team choose to create "Redio", a coroporate radio station that allows companies to play and stream live music across the Enterprise. In a nutshell, the solution included:

* Playlist creation - a user can select tracks from Spotify
* Scheduling of Playlists
* Ability to add adverts and "sweepers"
* Streaming of Spotify tracks from a central server to satellite PCs
* Streaming directly to client machines

The project was challenging enough; but we also needed to present to Microsoft. We did this via Lync and anyone from the Microsoft network could see what we did.

Full review by Dan Haywood: http://www.danhaywoodblog.com/2011/12/redweb-hack-day-produces-sharepoint-fis.html

Video of presentation: https://skydrive.live.com/redir.aspx?cid=9b7d796bd3e9e65c&resid=9B7D796BD3E9E65C!1228&parid=9B7D796BD3E9E65C!305&authkey=!AGjG73d414ceqm0


Here's just a couple of examples of the work we did...

* Our Senior Designer Luke produced an outstanding design for a SharePoint custom field.

With this field, end users can select tracks from Spotify using drag-and-drop. The meter allows users to add up to 30 minutes of music to a Playlist. After the Playlist has been created, it can be scheduled to play at a certain time.



* I created a Visual Web Part that shows the track currently playing. This uses the Bing API to dynamically download Album Art for the track.

Wednesday, November 9, 2011

Remove query string from url

I needed to delete the querystring value from a Url. The code I used to do this is right at the end of this post.

First though, here's the reason I needed to do it.

I found that if you call the SPWeb.GetFile method, with a Url that contains a query string, the value of Item for the returned SPFile will be null. Here's an example:


string url = "http://red-hb:8080/TestSite/Pages/Tamar.aspx?x=y";

using (SPSite site = new SPSite(url))
{
using (SPWeb web = site.OpenWeb())
{
SPFile file = web.GetFile(url);
Console.Write(file.Item["Title"]); // Item will be null.
}
}


OK, here's how I removed the query string:


string url = "http://red-hb:8080/TestSite/Pages/Tamar.aspx?x=y";

Uri uri = new Uri(url);

string queryString = uri.Query;

if (String.IsNullOrEmpty(queryString) == false)
{
url = url.Replace(uri.Query, String.Empty);
}

Thursday, November 3, 2011

"This solution contains no resources scoped for a Web application"

I created a SharePoint Solution that contained a single Feature. The Feature had a Receiver which is used to make web.config modifications.

I wanted to target these modifications at specific SharePoint web applications. However, when I ran the following PowerShell command, I got the message: "This solution contains no resources scoped for a Web application".

Install-SPSolution –Identity <WSP NAME>.wsp –WebApplication http://<TARGET APP URL> -GACDeployment -Force

Other people suggest not including the target web application url. I don't want to do this as it will affect all web applications, not just our own.

The workaround I used was to include the Solution assembly within its own package, and mark it as a "SafeControl".

I realise that this not ideal. Do you have a better solution?

The steps I followed were:

1) Open the Project Properties for the Solution, and set "Include Assembly in Package" to "False".

Include Assembly in Package

2) Edit the Package manifest and include the assembly from the project's own output. Add the assembly / namespace as a SafeControl.

Friday, October 28, 2011

SharePoint Anonymous Access

I was trying to change the Anonymous Access settings for a list, as per this screen:


SharePoint Anonymous Access checkboxes

However, when I checked the "Add Items" box and clicked OK, it did not save the changes. Everytime I repeated this and went back to the screen, the "Add Items" box was not checked.


The cause of the problem was that the Anonymous Policy for the SharePoint Application (that hosted the site) had been changed. By default this is set to "None". However, it had been set to "Deny Write".


SharePoint Anonymous Policy

There wasn't a good reason for this and switching it back to "None" fixed the problem.

Thursday, October 27, 2011

DataFormWebPart maximum field lengths

I used a DataFormWebPart to generate a custom edit form. Our client wanted to limit the maximum length of various fields on this form, but didn't want these to be applied site-wide.

The built-in SharePoint fields (FormField, TextField, NoteField, etc) don't have a "maxlength" property.

The solution was to modify the template for the various fields within the DataFormWebPart XSLT, to include RegularExpressionValidators.

Credit to Bart McDonough for this. His blog post relates to creating a new field type, but I tried it within the DataFormWebPart and it worked.

The nice thing about this is that the validation will take place on both the client and the server

Here is a sample from my DataFormWebPart XSLT file. This sets the maximum length of a text field to 80 characters.

Note that the curly braces in the regular expression have to be escaped. If you don't do this, the XSLT will break.



<SharePoint:TextField runat="server" id="ff1{$Pos}" ControlMode="Edit" FieldName="Title" __designer:bind="{ddwrt:DataBind('u',concat('ff1',$Pos),'Value','ValueChanged','ID',ddwrt:EscapeDelims(string(@ID)),'@Title')}">

<Template>

<asp:TextBox id="TextField" runat="server"/>
<asp:RegularExpressionValidator
ControlToValidate="TextField"
ValidationExpression=".{{0,80}}"
Text="Value cannot exceed 80 characters."
runat="server" />

</Template>

</SharePoint:TextField>

Wednesday, October 26, 2011

SharePoint Check "page layout"

In code, I had a reference to an SPFile object and I wanted to check if the SPFile was a page layout file.

I used code (similar to the sample below) to do this. It checks to see if the file's parent list is the master page / page layout library.

Maybe you know a better way?


string url = " -- ABSOLUTE PATH TO YOUR FILE -- ";

using (SPSite site = new SPSite(url))
{
using (SPWeb web = site.OpenWeb())
{
SPList masterPagelist = site.GetCatalog(SPListTemplateType.MasterPageCatalog);
SPFile file = web.GetFile(url);

if (file.Item.ParentList.ID == masterPagelist.ID)
{
// The file is in the master page library.
}
}
}

Monday, October 24, 2011

SharePoint SummaryLinks "Edit Properties"

While logged-in as a user with Contributor permissions, I noticed that the toolbar for a Summary Links field was not visible on the Edit Form of a publishing page.

This is is shown in the picture below:

SummaryLinks has no

I suspect this is a SharePoint bug as the toolbar was visible when the page was in WYSIWYG edit mode.

Also, the issue did not occur when logged-in as a Site Collection administrator.

A work-around to this issue is to give the user the Manage Lists permission. However, this is really not something you should consider lightly as it gives editors an awful lot of power.

I'm going to speak to Microsoft to see what they say about it and then I'll post an update....

UPDATE


Microsoft has acknowledged that this is an "Offbug" (as they call it). In other words, it's a bug in their code.


This will be fixed in a future hotfix or service pack. However, they will not / cannot give a date for the fix.

Tuesday, September 13, 2011

SharePoint Inline HTML Editor

One of our clients had very specific requirements for the way in which their editors manage the main body content of a page. Here is some background:

With the previous version of SharePoint (MOSS 2007), page editors could edit page content using a Rich Text editor that sat above the content field. This is shown below:

MOSS RichText Editor

With SharePoint 2010, the Ribbon provides the editing functionality, as shown below:

Ribbon Editor

Even though our client is using SharePoint 2010, they wanted to use the MOSS-style page editor, rather than the Ribbon. This was for a subset of editors, on one specific site.

One way to solve this is to switch the User Interface (UI) version of the site from "4", to "3" e.g. switch from the SharePoint 2010 UI to the MOSS UI. This is done via the SPWeb.UIVersion property.

We didn't want to change the UI version so in the end, the solution was to:

1) Create a custom edit form.
2) Change the control used to edit the page content from SharePoint:FormField to SharePoint:InputFormTextBox

The InputFormTextBox has some properties that allow Rich Text, which are shown below:

<SharePoint:InputFormTextBox TextMode="MultiLine" Rows="6" RichText="true" RichTextMode="Compatible" runat="server" />

Friday, September 9, 2011

SharePoint 0x810200c6 List Validation Failed

We use custom code to create a new Publishing Page:

SPWeb currentWeb = SPContext.Current.Web;

PublishingWeb publishingWeb = PublishingWeb.GetPublishingWeb(currentWeb);

PublishingPage page = publishingWeb.GetPublishingPages().Add(newPageName, newPageLayout);

This was failing with the error:

<nativehr>0x810200c6</nativehr><nativestack></nativestack>List data validation failed.

The error was caused because the Pages library had validation applied to it, which validated two date fields. The formula for the validation was:

=[Start Date and Time]<[End Date and Time]

When the page was created in code, the validation was fired, which failed because the two date fields are initially empty.

The solution to the problem was to change the validation formula to handle the initial values e.g.

=[Start Date and Time]<=[End Date and Time]

Tuesday, September 6, 2011

SharePoint The document contains invalid utf-8 encoded characters

We used SharePoint to index a website and got the message "The document contains invalid utf-8 encoded characters".

To fix this, modify the target site and replace special characters with their encoded equivalent. For example, replace any £ characters with &pound;. The same is true for ©, which should be replaced with &copy, etc.

Use the W3C validator to identify encoding issues.

Tuesday, July 5, 2011

"Activate Features" "The object has been updated by another user since it was last fetched"

I created a Feature Receiver to assign an Event Receiver to various content types. This was working fine. However, after a small update to the code, the package would no longer deploy and failed with the following message:

Error occurred in deployment step 'Activate Features': The object has been updated by another user since it was last fetched.

I discovered the problem was caused because I:



  1. Assigned the Event Receiver to a base content type (CT 1).


  2. Immediately after attempted to add the Event Receiver to a content type (CT 2) derived from the base content type (CT 1)

To solve the issue, I did not do step (1) above and just did step (2).

Wednesday, June 29, 2011

SharePoint Public Websites

This is how you can find a list of public web sites built using SharePoint...

To do this, I used Google to search for the phrase "Turn on more accessible mode". This phrase is rendered by most SharePoint pages yet is specific enough to restrict the number of non-SharePoint sites returned.

Try it for yourself: http://www.google.co.uk/search?q=%22Turn+on+more+accessible+mode%22

I'm aware of the list on WssDemo.com. However, I wanted to use Google to generate a dynamic list.

Monday, June 27, 2011

SharePoint "Corrupted Control Template"

I began seeing the error message "Corrupted Control Template" when I switched a Publishing Page into Edit Mode.

Eventually I tracked-down the issue....

1) Another developer had created a number of custom fields.
2) They had created a file called "fldtypes_custom.xml" (which is required to register the custom field types).
3) I renamed this file to something more specific.

To fix the issue I had to....

1) Delete the Web Application (including the associated Content Database)
2) Rename the file back to what it was before I changed it
3) Re-deploy the solution.

Friday, May 27, 2011

SharePoint PublishingPageImage src

For an article page, SharePoint stores the value of the Publishing Image field in a particular format. Here is an example:

<img alt="" src="/SiteCollectionImages/home.jpg" style="BORDER: 1px solid; ">

I wanted to extract the value of the "src" attribute. Here is the code I used:

string fullValue = String.Format("{0}", file.Item[FieldNames.PUBLISHING_PAGE_IMAGE]);


string src = String.Empty;

if (String.IsNullOrEmpty(fullValue) == false)
{
string xml= String.Format("{0}</img>", fullValue);
string src = XElement.Parse(xml).Attribute("src").Value;
}

Wednesday, May 25, 2011

SharePoint "Object reference not set to an instance of an object" Page Save

I'd created a custom page layout, applied it to a page and then tried to edit the page. Everything was fine until I clicked on one of the save options for the page. At this point the site blew-up with the following stack trace:

NullReferenceException: Object reference not set to an instance of an object.]
Microsoft.SharePoint.WebPartPages.WikiPageWebPartSaver.SaveWebPartsInRichText(SPWebPartManager wpmgr) +230

It took a bit of work but I tracked-down the cause. Essentially the Designer had given me some HTML mark-up which I'd pasted into the page layout. This mark-up contained an additional "form" element. When this was removed, the page-save worked correctly.

UPDATE

I don't remember the exact code, but it was something like the code below. The first form element is generated by SharePoint. The second form element was pasted-in by mistake.

<form id="aspnetForm" method="post" name="aspnetForm" action="default.aspx">

...

<form action="destination_url" method="get">
</form>


...

</form>

Friday, May 20, 2011

SharePoint "Item does not exist. It may have been deleted by another user"

I'd created an Event Receiver to handle the ItemDeleted event. I'd assigned this to a ContentType, which was then added to a Picture Library.

Click the image below to see what the code looked like. Initially, this seemed to work prefectly. (I'm using an image to show the code so that the text formatting is unmangled and read-able).



However, if I selected multiple pictures in the library and then clicked the "Delete" option from the library's menu, an unhandled exception was thrown which read "Item does not exist. It may have been deleted by another user".

I discovered the fix for this, which was to re-arrange the "try" blocks in my code. So instead of having the try-catch block surrounded by the try-finally block, I switched them so that the try-catch block is surrounded by the try-finally block.

I suspect the error was being generated because of a thread-timing issue, since (when the error occurred) the debugger wouldn't hit any breaks points in the code.

The re-worked code is shown below. I realise I could also reduce the code by using a try-catch-finally block, rather than 2 try blocks.

Thursday, May 19, 2011

SharePoint site "cannot be imported because its parent does not exist"

I ran a content deployment job from my farm to a farm on another machine. The job failed with the message:

The site /deleteme2/Lists/test1 cannot be imported because its parent does not exist.

Right now I cannot explain why this failed. "DeleteMe2" was a test site that I'd created and subsequently deleted. The site had defintely gone and my farm had no orphaned sites.

To work around the problem, I changed the deployment job so that it only exported a specific site, rather than the entire site collection.

This got me up-and-running and I'll continue to investigate.

Wednesday, May 11, 2011

SharePoint Always Prompts for Credentials

I had a SharePoint site running quite happily on my Dev VM. However, when I tried to connect to the site from my base machine, I was repeatedly prompted for credentials and could not connect.

This was surprising as the domain account I was logged-in as was the same for both the base machine and the Dev VM.

I tried a number of possible fixes, including:

1) Adding the site address to my Local Intranet zone
2) Disabling the loopback check
3) Checking that the firewall (running on the Dev VM) was not blocking access
4) Using a non-Internet Explorer browser

Nothing worked!

However, I thought I'd create a new SharePoint application and then try connecting to that. While doing this, the following error message was shown: "The trust relationship between this workstation and the primary domain failed."



The fix to this issue was to remove, then re-add the Dev VM to the domain. After I did this, I found the connection issue went away.

Wednesday, April 20, 2011

SharePoint Always Creates Subsites under Root Site

As I mentioned in one of my other posts, each developer in our SharePoint team runs an independent farm on a project-specific Virtual Machine.

One of our newer developers reported that, when they tried to create a subsite at a level 2 levels deep, the site was created, but it was created under the root site (only 1 level down).

It turns out that this was because they were accessing the site using "localhost", instead of the NetBIOS name of the server.

Friday, March 18, 2011

"Round Robin Service Load Balancer Event"

After installing SharePoint, you might see many error messages in the event log along the lines of: SharePoint Web Services Round Robin Service Load Balancer Event: EndpointFailure.

If you do, you're not alone.

Information about this error message is, at the time of writing, difficult to find. However, a Technet forum suggests that this is related to the SharePoint 2010 December Cumulative Update.

Indeed, we had applied this to the farm. However, I can also confirm that the February Update does not fix the issue.

Monday, March 14, 2011

stsadm "the server instance specified was not found"

When running an stsadm command that requires the "url" parameter, you may see the error message "the server instance specified was not found".

If you are doing this within a multi-server farm environment, consider on which server you are running the command.

Is it an application server or a web-front-end server? If it's the former, the server won't be running the "web application" service, which is required for the command to work properly.

Wednesday, March 9, 2011

Spence Harbar

Spencer Harbar If Spence Harbar played football, we'd all be singing "There's only one Spence Harbar".

Why do I say that? Read on...

When building a SharePoint 2010 server farm, (in my opinion) the most tricky bits to get right are: User Profile synchronization and Kerberos.

If you are planning to work in these areas and you haven't already come across Spence Harbar, I urge you take a look at his blog before you start.

He's produced some step-by-step guides for a successful installation, based on real-world examples and corrects some widely-held misconceptions.

Check out his posts here: User Profiles and Kerberos.

Wednesday, March 2, 2011

SharePoint “Unable to process Create message”

You may see this error message when you try to create a new User Profile connection: “Unable to process Create message”.

This can be caused for a number of reasons. However, in our case this was because:
  1. Our servers / user accounts were installed in an Active Directory whose Netbios name was different to the Fully Qualified Domain Name.
  2. The SharePoint 2010 December Cumulative Update had been applied to the farm.

This is a known issue, which Microsoft is investigating.

Thursday, February 24, 2011

SharePoint "The Product ID specified was not found"

Today I started the installation of a 4 server farm. The SharePoint 2010 setup media had been copied into a network folder location. I chose to copy that folder to all of the SharePoint servers, so that the setup program would run locally, rather than come across the network.

On each SharePoint server I ran the setup program and installed the prerequisites. This worked fine.

On one server, I then tried to install the main SharePoint program files but I got the following message: "The product ID specified was not found on the machine", as shown below.


Oddly this acutally worked on one of the servers, but for the other 3 it failed.

I can only assume that copying the setup folder to each server had somehow corrupted the files. Anyhow, the solution was instead to mount an ISO image as an optical drive on all servers, and that worked.

Monday, February 21, 2011

SharePoint Solution and Authored Artifact Development

Microsoft produced a useful article regarding designers and developers working together on SharePoint projects (albeit it's for MOSS, not SharePoint 2010).

However, the article does leave an unanswered question, which I address below.....

Based on the Microsoft article, our approach is this:
  1. All developers and designers have their own virtual machine, running an independent SharePoint farm.

  2. All assembly and artifact development takes place within Visual Studio - SharePoint Designer is not used.

  3. Team Foundation Server (TFS) is the only repository for source code.
We like this approach because:
  1. We can comply with ISO standards for source-control.

  2. Master Pages and Page Layouts are deployed in an uncustomised state.

However, consider this scenario: Developer A needs to create a content roll-up which rolls-up content from a deep site structure. In order to create the roll-up, Developer A needs to create all of the content on their own farm. Once they've checked-in the roll-up code into TFS, other developers can use the roll-up in their farms, but only after they have re-created the site structure - and that could take a long time to create.

In addition, suppose Developer A creates a roll-up that targets a particular list (by the list GUID). How do you ensure that the list is created with the same GUID on all farms?

What's needed is an easy way for content to be replicated between all of the farms.

There are several possible solutions to this:

  1. Back-up the content database in one farm and restore it to all of the other farms. This is not ideal as the process would delete any work-in-progress-content that a developer had created for their own use.

  2. Use SharePoint's built-in Content Deployment process. This will distribute newly created content between the farms, and doesn't have the "delete" issue described in the last point. However, as we mostly work with SharePoint Publishing sites, we have an issue in that you can only deploy content to a Publishing site collection that has not already had a site definition applied. This means you need a "master" farm, where all content is created, and from where content is deployed. This is not an ideal situation when you have multiple developers who need to create content and test locally on their own farm.

  3. Use "stsadm -o export" to package content to a file, which can be re-imported into another farm. This is our preferred method as it avoids the issues listed above. Exported file packages can be put into a shared folder or TFS, depending on your requirements.

Friday, February 18, 2011

SharePoint failed to retrieve field value

Issue: The Associated Content Type of a page layout is shown as "failed to retrieve field value".

After packaging and deploying some new page layouts, I went to the home page of a site collection and tried to put the default page into edit mode.

The following page error appeared: "Value does not fall within the expected range".

The stack trace wasn't very helpful. However, when I looked at the "Master Page" gallery using the Site Content and Structure tool, I noticed the issue described above. Here is a screen shot, with the problem highlighted in yellow:




I went back to the module definition for the page layout and compared it with some others in the same file.

The error was caused because of a missing # symbol, which should have preceeded the content type reference. This is shown below, again with the issue highlighted:

Thursday, February 10, 2011

LoadControl() Request failed

I was tearing my hair out over an issue with using the UserControl.LoadControl method from within SharePoint, which kept throwing this exception:

Exception Details: System.Security.SecurityException: Request failed.

We run our code using the least priviledge possible, which means creating a custom CAS policy. However, no amount of tweaking the CAS policy seem to fix the issue.

It seems this is a common issue (see this blog post). People who have commented on that blog suggest a number of solutions. However, I found the only solution was to:
  1. Call the LoadControl method from an assembly located in the GAC.
  2. Use the PermissionSet Assert method to obtain sufficient privileges
Here is an example of the code:

public static Control LoadControl(UserControl parentControl, string controlName)
{
Control control = null;

System.Security.PermissionSet permissionSet = new System.Security.PermissionSet(System.Security.Permissions.PermissionState.Unrestricted);
permissionSet.Assert();

try
{
string controlPath = String.Format("~/_controltemplates/{0}", controlName);
control = parentControl.LoadControl(controlPath);
}
finally
{
System.Security.CodeAccessPermission.RevertAssert();
}

return control;
}


Friday, February 4, 2011

Content controls have to be top-level controls in a content page

I made a change to a page layout to include a CSS file and started seeing an error message which said "Content controls have to be top-level controls in a content page".

This is how the markup looked; can you see the error?

<asp:Content contentplaceholderid="PlaceHolderAdditionalPageHead" runat="server">

<ContentTemplate>

<SharePointWebControls:CssRegistration name="/_layouts/1033/styles/Themable/search.css" runat="server" >

</ContentTemplate>
</asp:Content>


Did you spot the error?

The CssRegistration declaration was missing its closing tag. Once fixed, the page worked correctly.

Wednesday, February 2, 2011

I Love SharePoint - Mug

Being a SharePoint fanatic I had to get hold of an "I Love SharePoint" mug. Fortunately such mugs do exist and here is a picture of mine:




If you want to buy one yourself, you can order them from this site.

Saturday, January 29, 2011

Search - Click Through Relevancy

You may have heard that SharePoint 2010 search (not Foundation) includes "Click Through Relevancy". This means that, as more users click on a specific link in the search results, SharePoint will increase the link's ranking.

It made me wonder if Google use the same approach as part of their page ranking algorithm?

If it did, you could perhaps post links to a site with a special query string, making use of the Google "I'm feeling lucky" to simulate a click e.g.

http://www.google.com/search?q=redweb.com&btnI

Of course that would be too easy to abuse, which is why Google don't do it.

However, our in-house SEO experts told me that Google Instant search did allow something similar and was exploited.

Friday, January 28, 2011

SharePoint Relative Url

We have a number of page layouts which allow the user to enter a URL. SharePoint stores the value as an absolute value, along with a description.

(BTW, you can use the SPFieldUrlValue class to extract the URL and description).

Anyhow, I wanted to generate a relative path from stored absolute value. I used the following code to do it.

Maybe you know a better way.....?


SPFieldUrlValue spFieldUrlValue = new SPFieldUrlValue(fieldValue);

string targetUrl = spFieldUrlValue.Url;

using(SPSite site = new SPSite(targetUrl))
{
  return targetUrl.Replace(site.Url, String.Empty);
}

Tuesday, January 25, 2011

2 Level Navigation

I wanted to create a mini-sitemap which had the following criteria:
  1. Only show sites
  2. Only show 2 levels of navigation

This article gave me an insight and I was then able to come up with this as the solution:

<SharePoint:AspMenu ID="FooterGlobalNav" runat="server" DataSourceID="GlobalNavDataSourceFooter"
Orientation="Vertical" StaticDisplayLevels="2" MaximumDynamicDisplayLevels="0" UseSimpleRendering="true" />

<publishingnavigation:portalsitemapdatasource id="GlobalNavDataSourceFooter" runat="server"
sitemapprovider="CombinedNavSiteMapProvider" showstartingnode="false" startfromcurrentnode="false"
startingnodeoffset="0" trimnoncurrenttypes="Heading" treatstartingnodeascurrent="true" />





Friday, January 21, 2011

The resource cannot be found - CONTROLTEMPLATES

While working in our team environment, a colleague stated that the SharePoint site had gone done. A screen shot is shown below:






The error only occurred on the root site.


It turns out this was because the home page of the root site (default.aspx) uses a page layout which references some custom user controls in the CONTROLTEMPLATES folder and my colleague's VM did not have these.

Sunday, January 16, 2011

Hello World

This is my first post on my first ever Blog. I've just started a large SharePoint 2010 project and wanted to share my experience and pass on some of the things I learn along the way. Hopefully that will be useful to someone out there.

Cheers
Howard