If you would like to discuss anything, please contact me via email: Howard.Bayliss@sequence.co.uk
Monday, December 5, 2011
SharePoint Radio Station
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
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 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".
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:
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".
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
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"
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"
This is is shown in the picture below:
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
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:
With SharePoint 2010, the Ribbon provides the editing functionality, as shown below:
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
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
To fix this, modify the target site and replace special characters with their encoded equivalent. For example, replace any £ characters with £. The same is true for ©, which should be replaced with ©, 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"
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:
- Assigned the Event Receiver to a base content type (CT 1).
- 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
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"
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
<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
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"
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"
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
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
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"
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"
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
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”
This can be caused for a number of reasons. However, in our case this was because:
- Our servers / user accounts were installed in an Active Directory whose Netbios name was different to the Fully Qualified Domain Name.
- 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"
Monday, February 21, 2011
SharePoint Solution and Authored Artifact Development
However, the article does leave an unanswered question, which I address below.....
Based on the Microsoft article, our approach is this:- All developers and designers have their own virtual machine, running an independent SharePoint farm.
- All assembly and artifact development takes place within Visual Studio - SharePoint Designer is not used.
- Team Foundation Server (TFS) is the only repository for source code.
- We can comply with ISO standards for source-control.
- 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:
- 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.
- 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.
- 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
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
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:
- Call the LoadControl method from an assembly located in the GAC.
- Use the PermissionSet Assert method to obtain sufficient privileges
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
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
If you want to buy one yourself, you can order them from this site.
Saturday, January 29, 2011
Search - Click Through Relevancy
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
(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
- Only show sites
- 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
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
Cheers
Howard