ADFS 2.0 / Claims authentication / Sharepoint 2010
You encounter the following error message in your event log:
An operation failed because the following certificate has validation errors: [….] Errors: The root of the certificate chain is not a trusted root authority..
This might seem strange, because this will appear even if you have the CA certificate in your certificate store. The reason is that Sharepoint has it’s own registry of certificates, and you will have to add the CA there as well.
1. Open “ADFS 2.0 Management”
2. Expand Service – Certificates
3. Right click the primary (if more than one) certificate under Token-signing, and select View Certificate
4. Choose the Details tab, and click “Copy to file…”
5. Complete the wizard, saving the certificate as “DER encoded binary” (name it ADFSRoot.cer or something)
6. Copy the .cer file over to your Sharepoint server
Now you have to add this certificate to Sharepoints list of root authorities. You’ll be using the Sharepoint 2010 Management Shell for this operation:
1. Start Sharepoint 2010 Management Shell
2. Run the following two commands (change the path to where your .cer is located):
$root = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2("C:\TEMP\ADFSroot.cer")
New-SPTrustedRootAuthority -Name "ADFS Token SigningRoot Authority" -Certificate $root
3. The certificate properties will be listed as a confirmation that the certificate has been added.
If your certificate chain contains more than one certificate, you will have to do this with each one giving them a unique name.
Thanks to Steve Peschka for providing an excellent guide.
Sharepoint 2010 – access site usage statistics
OK, so you made the assumption that Microsofts Sharepoint team would have provided a simple way to access something as common (and not to mention extremely useful!) as site usage statistics. Which pages and resources are accessed
- at what time
- for how long
- how often
- the browser type
- http status
- and last but definately not least: by who.
And not only did you assume this would be easily accessible, you also told a client you’d have it done in a couple of hours. I assume some of you that ended up here either got lucky straight away, or you have already spent way more time than expected and added yet another element to your list of reasons why Sharepoint will make you loose your hair prematurely.
If you assumed that this data should be available somewhere you were right. The trick is to know how to access it from your custom web part. The data is stored in the WSS_Logging database, in a table called RequestUsage. You can run a simple query just to see what’s in there and which fields you have access to:
SELECT * FROM [RequestUsage]
Then you can start getting a bit more creative. You see, the RequestUsage table contains statistics for all sorts of requests – like requests to the MetadataWebService. So depending on your needs, filter out the type of document types / extensions / paths you are interested in. I needed just to know the hit count of .aspx pages in a specific sub site, so my query looked somewhat like this:
SELECT distinct(DocumentPath), COUNT(*) as DocCount FROM [RequestUsage] WHERE DocumentPath LIKE '/Marketing%' AND ( DocumentPath LIKE '%.aspx' ) GROUP BY DocumentPath
This is not a lesson in SQL, but that query gives me a nice list of all .aspx documents accessed under the Marketing sub site with the corresponding hit count. To get the top 5 out of that result, you’ll end up with something like this:
with cte as ( SELECT distinct(DocumentPath), COUNT(*) as DocCount FROM [RequestUsage] WHERE DocumentPath LIKE '/Marketing%' AND ( DocumentPath LIKE '%.aspx' ) GROUP BY DocumentPath ) select top 5 DocumentPath, DocCount from cte order by DocCount desc
So we have a query we would like to run, and then you can display the result in a web part. There are numerous ways to do that, and I won’t cover it here but I’ll show the C# code for running this query. The following code snippet is put together from my actual project, and should give you enough information to piece together a working method. Take note of how the connection string for the WSS_Logging database is retrieved:
// run with elevated privileges SPSecurity.RunWithElevatedPrivileges(delegate() { string connectionString = SPUsageApplication.DefaultApplication.UsageDatabase.DatabaseConnectionString; SqlConnection connection = new SqlConnection(connectionString); // build your query StringBuilder sb = new StringBuilder(); sb.Append("with cte "); sb.Append("as "); sb.Append("( "); sb.Append("SELECT distinct(DocumentPath), COUNT(*) as DocCount "); sb.Append("FROM [RequestUsage] "); // ... // add all the WHERE filters you want here // ... sb.Append(" GROUP BY DocumentPath "); sb.Append(""); sb.Append(") select top " + ItemCount + " DocumentPath, DocCount from cte order by DocCount desc"); string sql = sb.ToString(); SqlCommand command = new SqlCommand(); command.Connection = connection; command.CommandText = string.Format(sql, SPContext.Current.Web.ServerRelativeUrl); command.CommandType = System.Data.CommandType.Text; command.Connection.Open(); SqlDataReader reader = command.ExecuteReader(); while (reader.Read()) { // access the fields, for example document name string docName = reader["DocumentPath"].ToString().Substring(reader["DocumentPath"].ToString().LastIndexOf('/') + 1); docName = HttpUtility.UrlDecode(docName); // build an HTML table, add items to a list or whatever you prefer // .. } // close the db connection command.Connection.Close(); }
The magic lies in how you build and define the filter to suit your requirements.
Sharepoint 2010 – Rename Contextual Search Label
One of the elements you don’t have control over in a Sharepoint 2010 environment is the label for the contextual search option in the search drop down list (“This Site: “ and the name of the current site):
The dynamic nature of the contextual search definition means that wherever you are in your Sharepoint solution where the search drop down list is visible you will have a “This Site: “ option.
In some cases you might want to change this text. One annoying situation is if your solution has a series of sites that share a common prefix, and this prefix is just long enough to take up all the visible real estate of the drop down box. Your users will then see “This Site: Long Site Prefix” for all sites, instead of the last part of the name which is actually unique.
This can be solved by adding some javascript to your page (non-jQuery, so no references required). Add a Content Editor web part and edit the contents by clicking the HTML drop down and selecting “Edit HTML source”:
Insert the following javascript:
<script type="text/javascript"> function SearchScDDLInj() { var srhScDDL = document.getElementById("ctl00_PlaceHolderSearchArea_ctl01_SBScopesDDL"); if (srhScDDL != null) { srhScDDL.options[0].text = "My custom value"; } } SearchScDDLInj(); </script>
This script will search for the drop down list (identified by ‘ctl00_PlaceHolderSearchArea_ctl01_SBScopesDDL’) and replace the first value with “My custom label”.
Save the webpart and the search drop down list should now display your own value. If not, use something like the developer tools in IE and search for the correct id for the element (not name!). The easiest way is to search for whatever value currently displayed for contextual search (“This Site: Prototyping” in my case”) and then get the ID of the placeholder:
And there you go:
Sharepoint 2010 – display custom properties on Profile page
Tip #1:
Changing the order of properties displayed in the user profile page of MySite is a PITA if doing it through Central Admin (User Profile Service Application –> Manage User Properties). To move the item higher or lower you’ll trigger a postback for each and every single step, which takes a ridiculous amount of time. So download this tool from Codeplex and save yourself a bucketload of time.
Tip #2:
There are a few user profile properties that are shown by default, while the rest are visibly only by clicking the “More information” link. Changing the order of these is either simple (see tip #1) or time consuming and horrendous (use Central Admin). The properties visible by default (typically office and contact information) are not affected by the order you specify in Central Admin so how do you change them? And how do you add more properties? Open up the web application you use for MySite (usually something original like http://mysite) in Sharepoint Designer. Find Profile.aspx under “All files” and “Edit File in Advanced Mode”. Now you can use WYSIWYG editor capabilities to shape and alter the layout, and adding a new property only requires a new div tag with a reference to the property name (get the correct property name from “User Profile Properties” in Central Administration. Edit the details for the property you want to display, and get the “Name” property, e.g. “Pager” in this example):
<div style="padding-left: 20px;" class="ms-contactcardtext3" id="ProfileViewer_ValuePager"> Pager number: <SPSWC:ProfilePropertyValue PropertyName="Pager" dir="ltr" runat="server"/> </div>
Sharepoint 2010 – how to show error details when debugging
Showing actual error details with the stacktrace is usually a quick change in web.config for any ASP.NET web application. For Sharepoint 2010 a few more steps are required, as there are several web.config files spread around.
In my case, the web.config files to change were:
C:\inetpub\wwwroot\wss\VirtualDirectories\[your_web_app]
Set <customErrors mode=”On”> to Off
Set <SafeMode .. CallStack=”False”> to True
Set <Compilation batch=”False” to True and <Compilation Debug=”False” to True
C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\TEMPLATE\LAYOUTS
Set <customErrors mode=”On”> to Off
Ensure <compilation batch=” ”> is Off
C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\CONFIG
Set <customErrors mode=”On”> to Off
Sharepoint 2010 – disable client side validation while in edit mode
If your web part uses client side validation you would have experienced how annoying this is when opening the page in Edit Mode. I knew there had to be a way to turn this off, but it wasn't until today I actually spent a few minutes figuring it out. The solution is to add an IF statement in the Page_PreRender() method to check the current page mode, and then disable the client side script for the validation controls:
protected void Page_PreRender(object sender, EventArgs e)
{
// determine if page is in Edit mode
WebPartManager wp = WebPartManager.GetCurrentWebPartManager(Page);
if (wp.DisplayMode == WebPartManager.EditDisplayMode)
{
// disable all client side validation
RequiredFieldValidator1.EnableClientScript = false;
RequiredFieldValidator2.EnableClientScript = false;
ValidationSummary1.EnableClientScript = false;
} }
Sharepoint 2010 – programmatically set workflow initiation parameters
If you trigger workflows from the code behind of a custom webpart you might want to set some of the workflow initiation parameters to runtime values. I’ve seen some pretty ugly attempts to do this by alternating the SPWorkflowAssociation.AssociationData object using string.Replace for instance.. To save others the time and effort figuring out this I thought I’d share a method I wrote where this is done in a more proper and reliable way.
For simplicity the namespace is hardcoded, but you should be able to figure that part out for yourself. This is the default namespace, and will work unless you’ve tampered with it.
It pretty much just accepts the original association data (XML based) and the name of the initiation parameter plus the new value (this is only for string based variables, but you could easily add support for other types as well).
private static string AddVariableToWorkflowAssociationData(string originalAssociationData, string variableName, string variableValue) { XNamespace dfs = "http://schemas.microsoft.com/office/infopath/2003/dataFormSolution"; XNamespace d = "http://schemas.microsoft.com/office/infopath/2009/WSSList/dataFields"; var associationDataXml = XElement.Parse(originalAssociationData); if (associationDataXml == null || associationDataXml.Element(dfs + "dataFields") == null || associationDataXml.Element(dfs + "dataFields").Element(d + "SharePointListItem_RW") == null || associationDataXml.Element(dfs + "dataFields").Element(d + "SharePointListItem_RW").Element(d + variableName) == null) { _log.Warn("AddVariableToWorkflowAssociationData() unable to find node '" + variableName + "' in association data"); return originalAssociationData; } _log.Info("Setting workflow parameter '" + variableName + "' to '" + variableValue + "'"); var nodeToChange = associationDataXml.Element(dfs + "dataFields").Element(d + "SharePointListItem_RW").Element(d + variableName); nodeToChange.SetValue(variableValue); return associationDataXml.ToString(); }
Invoke this method by getting a reference to the workflow you want to trigger (SPWorkflowAssociation), call my method with the original association data, and use the return value when starting the workflow:
string enhancedAssociationData = AddVariableToWorkflowAssociationData(wrkFl.AssociationData, "MyVeryOwnAssociationParameter", "SomeCrazyValue!!"); enhancedAssociationData = AddVariableToWorkflowAssociationData(enhancedAssociationData, "AnotherAssociationParameter", "AndYetAnotherCrazyValue"); siteColl.WorkflowManager.StartWorkflow(record, wrkFl, enhancedAssociationData, true);
Some of this code was altered on the fly for this blog post so compilation is not guaranteed. However, if you’re this deep into it to start with you should be capable of resolving that anyway!
Sharepoint 2010 Custom view within document set library
Problem: you have a document library, containing one or more custom document sets. The document library itself has a view showing columns related to the document set (document set status, for instance), but when you open the document set itself you may want to display other columns that are document specific (like a status for the current document, plus some meta data fields). This might seem impossible to start with, because it is not an option in the document set content type definition, and if you attempt to change the view within the document set you’re taken to the settings page for the document library.
Fortunately, there is a way and here’s how.
1. Define a new view for the document library, with the columns you want to display within the internal library of the document set (for instance “document status”)
2. Go the the document library settings (From the library tab of the ribbon)
3. Choose the document set content type from Content Types (it has to be accessed from here, call Microsoft and ask why the ¤%# that is!)
4. Select Document set settings
5. You will now see a drop down list under “Welcome page view” where you can select default view
There you have it: different views in the document library and within the document set.
Sharepoint 2010 – webpart zone padding / spacing
To add some padding between the webparts within a webpart zone either add this in your custom .css:
.ms-PartSpacingVertical
{
margin-bottom: 0px;
}
.ms-PartSpacingHorizontal
{
margin-right: 20px;
}
Or, if you just want it on a specific page while the rest of your site is unaffected, use the semi-dirty method of adding a Content Editor Webpart with a <style> element (edit the HTML source):
<style type="text/css"> .ms-PartSpacingVertical { margin-top: 20px; } .ms-PartSpacingHorizontal { margin-right: 20px; } </style>
Sharepoint 2010 – complete development environment
If you are getting into Sharepoint development (professionally or of own interest) you need an environment containing a lot of Microsoft products. Even though you’ll get far with just Sharepoint 2010 and Visual Studio 2010 running on your own machine (preferrably 64 bit Windows Server R2, but you can get it running on Windows 7 as well), a more “production like” environment will be much better. For instance, having Active Directory available is a major advantage.
Microsoft has been generous with us here (well of course, because you would never pay hundreds of dollars up front to check out what this Sharepoint hype is all about….). They have put together a VHD image containing a whole bunch of stuff for most Sharepoint development needs.
Virtual machine “a” contains the following pre-configured software:
- Windows Server 2008 R2 Standard Evaluation Edition x64, running as an Active Directory Domain Controller for the “CONTOSO.COM” domain with DNS and WINS
- Microsoft SQL Server 2008 R2 Enterprise Edition with Analysis, Notification, and Reporting Services
- Microsoft Office Communication Server 2007 R2
- Microsoft Visual Studio 2010
- Microsoft SharePoint Server 2010 Enterprise Edition
- Microsoft Office Web Applications
- Microsoft FAST Search for SharePoint 2010
- Microsoft Project Server 2010
- Microsoft Office Professional Plus 2010
- Microsoft Visio 2010
- Microsoft Project 2010
- Microsoft Office Communicator 2007 R2
Thanks Bill!

