Tag Archives: Development

Active Directory Images are not imported by the SP2010 User Profile Import

This is something that I found when starting a new SharePoint 2010 (SP2010) Intranet project. You see, my client has quite a simple requirement, at least it seems that way at first.

They have an HR database which they use to store everything from employee details to security card information. For this reason they manage all of the employee photos here, and they are pushed into Active Directory (using the LDAP “jpegPhoto” attribute) to make them available in applications like Outlook.

So … to put it quite simply .. they don’t want to use SharePoint to upload their photos. In fact, they already have their photos in AD .. they just want to pull them into SharePoint 2010.

Can’t we just map the Profile Property to AD and Import the value?
So here is where we hit the roadblock.. The Active Directory “jpegPhoto” attribute is of type “Binary Data” and the SharePoint 2010 User Profile property is of type HyperLink (as it typically links to an image in an Asset Library in the My Site Host site collection).

As a result, you cannot import it using SharePoint 2010 functionality (although it may be possible if you have also purchased the more sophisticated “ForeFront Identity Manager Synchronisation Server” product).

Options ??
Well .. SharePoint IS used as a development platform so there are some options. Obviously there is a full API for reading and writing in and out of the User Profile database (some more accessible than others).

There are a few good blog articles that you can follow if you want to build your own import function. If you are happy to wait a while longer then I already have my own solution which I will be posting up with the following features:

UPDATE – Full Source code and WSP now published

* WSP Package
* Farm scoped feature, which installs a Timer Job attached to the MySite web application
* Iterates through all User Profiles, and finds and extracts Binary image data from Active Directory
* Automatically creates thumbnailed images in the My Site Host Asset Library
* Automatically updates User Profiles to point to those new images

During my research Glyn Clough also pointed me in the direction of another solution which allows you to do the same using a Console Application… personally I prefer the more “SharePoint” route of Timer Job and WSP package 🙂

In the meantime, you can feel free to avail yourselves of these posts:

How to: Achieve Count(*) on a large SharePoint list

This has been a mission of mine for a while now (before I went on holiday and took a 2 week hiatus from all things SharePoint :)).

One of the clients I’ve been working with has been trying to replicate a pretty simple operation (by normal development standards). They have a SharePoint list with a LOT of items in it (we are talking 200,000 list items and above) and includes some Choice fields.

They want to return a count of how often each choice value is being used. Now, if you were using SQL Server you would simply do the following pseudo-SQL:

select count(*) from myList group by myChoiceField

At first look in SharePoint this is not possible:

  • There is no “count” operation in CAML, nor any other kind of aggregation function
  • SharePoint Search “full text query” does not support the count(*) operator (or anything similar)
  • The only reference to aggregations is in the SPView.Aggregations property .. this is only used by the rendered HTML and the values are not returned in the result set.

Now .. I know that you can get count values on a list, if you create a View with a Group By then it shows you the number of items in each group, so it MUST be possible! So my mission started

List view with groups
We want to replicate this behaviour,
but programmatically!

First.. we need a test environment
The first thing I did was create a really big list. We are talking about 200,000 list items, so you can’t just pull all the items out in an SPQuery (as it would be far too slow!).

I generated a simple custom list. I add a choice field (with optional values of 1-20) and then generated 200,000 list items with a randomly assigned choice value (and a bunch of them without any choice value at all .. just for laughs).

Now I could play with my code

Attempt Number 1 – Retrieve all list and programmatically calculate the counts (fail)
I kinda knew this wouldn’t work .. but I needed a sounding board to know HOW bad it really was. There are 200,000 items after all, so this was never going to be fast.

  • Use SPQuery to retrieve 2 fields (the ID, and my “choice” field).
  • Retrieve the result set, and iterate through them, incremementing an integer value to get each “group” count value

This was a definite #fail.To retrieve all 200,000 list items in a single SPQuery took about 25 seconds to execute … FAR too slow.

Attempt Number 2 – Execute separate query for each “group” (fail)
I was a little more positive with this one … smaller queries execute much faster so this had some legs (and this is certainly a viable option if you only want the count for a SINGLE group).

  • Create an SPQuery for each of the “choice” values we want to group by (there are 20 of them!)
  • Execute each query, and use SPListItemCollection.Count to get the value

Unfortunately this was another spectacular #fail. Each query executed in around 2 seconds .. which would be fine if we didn’t have to do it 20 times! 🙁 (i.e. 40 second page load!!)

Attempt Number 3 – Use the SPView object (success!)
Ok .. so I know that the SPView can render extremely fast. With my sample list, and creating a streamlined “group by” view it was rendering in about 2 seconds (and thats on my laptop VM! I’m sure a production box would be much much quicker).

The main problem is … how do you get these values programmatically?

The SPView class contains a “RenderAsHtml” method which returns the full HTML output of the List View (including all of the group values, javascript functions, the lot). My main question was how did it actually work? (and how on earth did it get those values so quickly!)

I started off poking into the SPView object using Reflector (tsk tsk). The chain I ended up following was this:

  • SPView.RenderAsHtml() –>
    • SPList.RenderAsHtml() (obfuscated … arghhhh)

So that was a dead end .. I did some more poking around and found out that SPContext also has a view render method …

  • SPContext.RenderViewAsHtml() –>
    • SPContextInternalClass.RenderViewAsHtml() –>
      • COM object ! (arghhhh)

Now .. the fact that we just hit a COM object suggests that we are starting to wander towards the SQL queries that get executed to retrieve the view data .. I didn’t want to go anywhere NEAR that one, so I decided to leave it there and perhaps try using the output HTML instead (nasty .. but not much of a choice left!).

using (SPSite site = new SPSite(https://myspsite))
{
SPList list = site.RootWeb.Lists[“TestList”];
string strViewHtml = list.Views[“GroupedView”].RenderAsHtml();
}

Having done this we now have the HTML output of our view (and this code takes about 2-3 seconds to execute … fast enough for my laptop .. we can always cache the value if needed).
 
Looking through the DOM output in the browser, it was possible to identify the “group” element by their attributes. It is a TBody node with both an ID attribute and a “groupString” attribute (the GroupString is the important one, as it tells us the view is configured to “Group By”).
 
What I needed next was a way of getting the actual values out of the HTML. For this I used the extremely awesome “HTML Agility Pack” from Codeplex. This is a set of libraries that allow you to parse DOM elements, including both plain “poorly formed” HTML as well as XHTML, and then use XPath queries to extract any values you want (much in the same way you would normally use the XML namespace for XHTML).
 
This gave me the TBODY node, and from there I could use string manipulation on the “InnerText” to pull out the group name and the count value 🙂

// Using HTML Agility Pack – Codeplex
// load the HTML into the HtmlDocument object

HtmlDocument doc = new HtmlDocument();
doc.LoadHtml(strViewHtml);

// retrieve all TBODY elements which have both
// an ID and groupString attribute
HtmlNodeCollection nodes = doc.DocumentNode.SelectNodes(“//tbody[@id][@groupstring]”);

if (nodes != null)
{
foreach (HtmlNode node in nodes)
{
// extract the Group Name
string strGroupName = node.InnerText.Substring(node.InnerText.LastIndexOf(“ ”)+6);
strGroupName = strGroupName.Substring(0, strGroupName.IndexOf(“&#”)-1);
Console.Write (“Group: ” + strGroupName + “, “);

// extract the number of items
string strValueText = node.InnerText.Substring(node.InnerText.LastIndexOf(“(“) + 1);
Console.WriteLine(“Number of Items: ” + strValueText.Substring(0, strValueText.Length – 1));
}
}

As you can see I’m doing some rather nasty SubString statements.. there may well be a quicker and cleaner way to do this using Regex .. this was more a proof of concept than anything else 🙂

Result!

Console output, showing group names and counts.
3 seconds isn’t bad, running on a “single server” laptop VM image 🙂

The end result was 2-3 second bit of code, retreiving Group By, Count values for a list with 200,000 list items.

Not bad for an afternoons work 🙂

Attempt 4 – Do the same thing in JQuery (kudos to Jaap Vossers)
This was actually the original solution, I asked Jaap if he could look at this if he had spare time, as I knew he had a lot of JQuery experience (and he blew me away by having it all working in under 30 minutes!).

Basically it uses pretty standard JQuery to go off and retrieve the HTML content from another page, scraping the HTML and pulling back the values. Same as the C# it grabs the group TBody, then walks down the DOM to retrieve the text value that it outputs.

The speed is roughly the same as the actual view itself. I’m sure some more JQuery could be employed to pull out the specific values and do more with them, but the concept appears to be sound:

<script type=”text/javascript” src=”https://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js”></script>

<script type=”text/javascript”>
$(document).ready(function(){

// you will need to change this URL
var url = https://myspsite/Lists/MyList/GroupedView.aspx;

var groupings = [];

$.get(url, function(data) {
$(data).find(“tbody[id^=titl][groupString] > tr > td”).each(

function(index, value){
groupings.push($(this).text());
}
);

$(“#placeholder”).append(“<ul></ul>”);

$.each(groupings, function(index, value){

$(“#placeholder ul”).append(“<li>” + value + “</li>”)
});
});
});

</script>
<div id=”placeholder”></div>

tada .. (thanks Jaap!)

Result from JQuery output,
dropped into a Content Editor Web Part

Summary
Well .. I know doing HTML scraping isn’t pretty, but seeing as the code is MUCH faster than anything else I’ve seen (and is stuck in the middle of a COM object) there didn’t seem to be much choice.

By all means, feel free to let me know if you have any alternatives to this.

RCWP Part 3 – Edit Web Part using a Ribbon modal dialog

Also check out the other part of the series:

This follows on from Part 1 (where we created a “Related Content Web Part”) and Part 2 (where we added a contextual tab to the Ribbon).

This post summarised the final part of this Web Part (which we completed in the final session of the day of SPRetreat last Saturday).

We wanted to provide a pop-up window, accessed through our new Contextual Tab in the Ribbon, which allowed us to easily modify some web part properties.

The basis of this was quite straight-forward, and it certainly starts off quite easy.
We created a new Application Page (RCWP_SetFieldValue.aspx) which would contain the code to update our Web Part Properties.

In this file we added a simple ASP.Net Label, Drop Down List and button.

<asp:Content ID=”Main” ContentPlaceHolderID=”PlaceHolderMain” runat=”server”>
<p>
    This allows you to set the field value for the <strong>Related Content Web Part</strong>
</p>
<asp:Label runat=”server” ID=”lblChoice” Text=”Select Field:” AssociatedControlID=”ddlFields” /><br />
<asp:DropDownList runat=”server” ID=”ddlFields” /><br />
<asp:Button runat=”server” ID=”btnNike” Text=”Just Do It!” />
</asp:Content>

Back in Part 2 we created a JavaScript file which was use for the “Command” events for our Buttons (yes .. I told you we’d be looking at that again!).

Here we are going to modify one of the Buttons so that it throws up a SharePoint Modal Dialog with our Application Page in it.

The code below is modified from the original MS Blog Article I referenced in Part 2 (called “How to create a Web Part with a Contextual Tab”).

if (commandId === ‘CustomContextualTab.GoodbyeWorldCommand’) {
            //alert(‘Good-bye, world!’);
            var options = {
                url: ‘/_layouts/SPR3/RCWP_SetFieldValue.aspx,
                title: ‘Set Field’,
                allowMaximize: false,
                showClose: true,
                width: 800,
                height: 600
            };
            SP.UI.ModalDialog.showModalDialog(options);
        }

I have basically changed the JavaScript for the “GoodbyeWorldCommand” button so that it does something different.

I am using the new SP.UI.ModalDialog namespace in the SharePoint ECMAScript to pop up a modal dialog window.

(Note – I also changed the display text to “Set Field” .. and deleted the other button to clean up the ribbon a bit)

But don’t forget that our Application Page is running from _layouts … it’s in a completely different place to our Web Part so this really isn’t enough for our page to work. In order to do anything else our Layouts page would need the following information:

  • The Page that the web part is on (URL)
  • Which Web Part to update on that page (Web Part ID)

The URL of the current page is easy enough using JavaScript (location.href) but the Web Part ID … this represented a new challenge.

How do you get the server-side Web Part ID through JavaScript?

This problem took the entire final hour of the day (Session 5) and took quite a bit of research and web searching. Eventually (after a few suggestions) we hit upon the answer:

Back in Part 2 we created a JavaScript file which was used to register our Contextual Tab. The JavaScript file that registers the Contextual Tab contains a reference to a “PageComponentId”.

getId: function ContextualTabWebPart_CustomPageComponent$getId() {
    return this._webPartPageComponentId;
}

Thes pecific instance of our Web Part had a “PageComponentID” of “WebPartWPQ2” and after some digging we found it in the Source of the page!

<div WebPartID=”866ef42d-6626-45e0-af9c-a00467ed2666″ WebPartID2=”1ad9529a-5e86-4e7c-9d4d-022a1fa6e6c0″ HasPers=”false” id=”WebPartWPQ2″ width=”100%” class=”ms-WPBody noindex ms-wpContentDivSpace” allowRemove=”false” allowDelete=”false” style=”” >

The attribute that REALLY stands out though is the WebPartID:

WebPartID=”866ef42d-6626-45e0-af9c-a00467ed2666″

This is clearly a GUID value, referring to the server-side Web Part ID for that instance of the Web Part.
So .. how do we get this to our dialog.. well, good old trusty document.GetElementById() (we could have used JQuery, but I didn’t want to have to install the framework .. and don’t forget .. I only had 1 hour to get this working at SPRetreat!!)

Using this information, I could modify my JavaScript to retrieve these values, and pass them through to my Modal Dialog.

// get the Web Part DIV element
            var element = document.getElementById(this._webPartPageComponentId);
            // extract the Web Part ID (as a GUID object)
            var wpID = element.attributes[“WebPartId”];
            // pass through the URL and Web Part ID
            var options = {
                url: ‘/_layouts/SPR3/RCWP_SetFieldValue.aspx?wpID=’ + wpID.nodeValue + ‘&url=’ + location.href,
                title: ‘Set Field’,
                allowMaximize: false,
                showClose: true,
                width: 800,
                height: 600
            };
            SP.UI.ModalDialog.showModalDialog(options);

Note – as the Web Part ID is of type HTML Attribute, we need to use the “NodeValue” property instead of toString();

So .. first off, in our Application Page we can use the URL to retrieve the fields from the page’s Content Type and populate our Drop Down List.

protected void Page_Load(object sender, EventArgs e)
        {
            TargetUrl = Request.QueryString[“url”];
            // remove any query strings
            if (TargetUrl.IndexOf(“?”) != -1)
            {
                TargetUrl = TargetUrl.Substring(0, TargetUrl.IndexOf(“?”));
            }
            if (!Page.IsPostBack)
            {
                ddlFields.Items.Clear();
                SPFile file = this.Web.GetFile(TargetUrl);
                foreach (SPField field in file.Item.Fields)
                {
                    if (!field.Hidden)
                    {
                        ListItem item = new ListItem(field.Title, field.StaticName);
                        ddlFields.Items.Add(item);
                    }
                }
            }
            btnNike.Click += new EventHandler(btnNike_Click);
        }

I did a bit of string manipulation on the URL to make sure we trim out any URL query strings, and then use that to retrieve an SPFile object.

We then just iterate through the SPListItem.Fields collection, adding any fields that are not hidden.

Note – we are using an ASP.Net ListItem object in the Drop Down List, so that we can use the Display Name in the drop-down, but store the Static Name as the value .. it’s the Static Name we need to save to our Web Part!

The next bit is under our Click event. We can now use the URL to get the SPLimitedWebPartManager for the page, and pass through the Web Part ID property, and it would retrieve the instance of my Web Part (allowing me to set the field value).

protected void btnNike_Click(object sender, EventArgs e)
       {
           // get Web Part ID
           wpID = Request.QueryString[“wpID”];
           // retrieve the Web Part Panager for the URL
           SPFile file = this.Web.GetFile(TargetUrl);
           SPLimitedWebPartManager wpm = file.GetLimitedWebPartManager(PersonalizationScope.Shared);
           // get the safely-casted web part object
           RelatedContentWebPart.RelatedContentWebPart wp =
               wpm.WebParts[new Guid(wpID)] as RelatedContentWebPart.RelatedContentWebPart;
           if (wp != null)
           {
               // set the web part property, and save settings
               wp.FieldName = ddlFields.SelectedValue;
               wpm.SaveChanges(wp);
           }
           // close the modal dialog
           this.Context.Response.Write(“<script type=’text/javascript’>window.frameElement.commitPopup();</script>”);
           this.Context.Response.End();
       }

So .. we should be done…

Build / Deploy / Test

So .. a long journey but worth it, five different 1 hour sessions and a great day at #SPRetreat .. but definitely worthwhile, and a new “Related Content Web Part” to boot!

A massive thanks to Andrew Woodward (21Apps) and Ben Robb (CScape) for organising the event, the venue and the food! (great food!!!)

Source Code

Sorry it took so long for me to get it all online, I was very busy then went on holiday. You can find all of the source code downloadable from my SkyDrive here:

https://cid-60f12a60288e5607.office.live.com/self.aspx/SPRetreat/SPR3.zip

RCWP Part 2 – Web Part with Ribbon Contextual-Tab

Also check out the other part of the series:

This follows on from Part 1, where we created a “Related Content Web Part” (RCWP) which would dynamically return search results based on the value of a field on the current page.

This post summarises the second-phase of that Web Part (which we started in session 4 of SPRetreat) to provide an easier method for the Content Editors to cherry-pick which field they wanted to use for the keyword search value. Seeing as me and my session 4 partner hadn’t done anything with Contextual Tabs before, we decided to give that a crack.

I’m not going to cover every single details of this. There are 2 fantastic articles:
Chris O’Brien (MVP) has a great 4-Part series titled “SharePoint 2010 Ribbon Customisation series” which is a must-read if you want to understand more about Ribbon development work.

There is also an excellent step-by-step guide on the Microsoft SharePoint Developer Documentation Blog called “How to create a Web Part with a contextual tab”.

In my example, I used the Microsoft blog’s example code, but there are plenty of good tutorials for this on the web. I’m not going to copy the same information in the blog article here, but the summarised core points are as follows:

  • Your Web Part must implement the Interface IWebPartPageComponentProvider(Microsoft.SharePoint.WebControls).
  • The Interface involves a WebPartContextualInfo property, which you use to register you “contextual” event
  • You will need a JS file to stored your “actions”
  • You will need XML configuration to register the definition of your “tab” and it’s controls.

So first off, we need to modify our web part to implement the Interface IWebPartPageComponentProvider:

public class RelatedContentWebPart : CoreResultsWebPart,
    IWebPartPageComponentProvider
{
    // omitted for clarity
}

Now, before we implement the Interface we need to setup a few methods and properties.
First up is the XML schema for both the Tab Template and the Tab itself. It’s a lot of XML so I’m not going to post it here, but I basically copied the XML provided on the MS Blog post, so you should find it easy enough to go and fetch it from there or just use my Full Source Code (in Part 3).

A snippet of the first part is below;

private string contextualTab = @”
   <ContextualGroup Color=””Magenta””
     Command=””CustomContextualTab.EnableContextualGroup””
     Id=””Ribbon.CustomContextualTabGroup””
     Title=””Related Content Web Part””
     Sequence=””502″”
     ContextualGroupId=””CustomContextualTabGroup””>
          <Tab
              Id=””Ribbon.CustomTabExample””
              Title=””Filtering Settings””
              Description=””This holds my custom commands!””
// remainder omitted for clarity

You can see that we have created a string called “contextualTab” that references a “ContextualGroup”. This has a colour, as well as a unique ID that we need to create. The Title will appear in the ribbon as the “contextual” group, which will span across multiple tabs (if you have multiple tabs in the same “contextual group” of course!).

Note – I have changed the title and description of my Tab and the Contextual Group, but everything else is the same as the MS Blog!

We also have a standard Ribbon “Tab” declaration, with an Id value which we will need later) as well as the Tab Title and Description.

Further down in the XML is a reference to the “Buttons” that we are going to have on our tab.
(Note – the code below is an exact copy of the “MS Blog Article” code .. we will be changing this later on!)

<Button     Id=””Ribbon.CustomTabExample.
    CustomGroupExample.GoodbyeWorld””
    Command=””CustomContextualTab.GoodbyeWorldCommand””
    Sequence=””15″”
    Description=””Show the Goodbye World text””
    LabelText=””Goodbye World!””
    TemplateAlias=””cust1″”/>

Make a note of where these button controls are, because we’re going to need to modify this in Part 3 of this post!

There is also another string created called “contextualTabTemplate” which you can use for the layout configuration.

private string contextualTabTemplate = @”
          <GroupTemplate Id=””Ribbon.Templates.CustomTemplateExample””>
            <Layout
              Title=””OneLargeTwoMedium”” LayoutTitle=””OneLargeTwoMedium””>
              <Section Alignment=””Top”” Type=””OneRow””>
                <Row>
                  <ControlRef DisplayMode=””Large”” TemplateAlias=””cust1″” />
                </Row>
              </Section>
// remainder omitted for clarity

So … now we have all of our XML defined we need to create a JavaScript file. The MS Blog article includes a JS file called “CustomContextualTabPageComponent.js” which deploys directly to the 14\Template\Layouts\ folder.
This contains a whole load of JavaScript for the Tab, Group and Button items in your XML file.

Important Note – The Command and Enable scripts use in your XML are in this JS file. If you start changing names you will need to manually keep these files in check.. they are XML and JS files so no compile errors or warnings! … except this one 😉

Probably the most important section in this file is that which handles the “Command” event for your buttons:

handleCommand: function ContextualTabWebPart_CustomPageComponent
    $handleCommand(commandId, properties, sequence)
{
    if (commandId ===
        ‘CustomContextualTab.HelloWorldCommand) {
            alert(‘Hello, world!’);
    }
    if (commandId ===
        ‘CustomContextualTab.GoodbyeWorldCommand’) {
            alert(‘Good-bye, world!’);
    }
}

Again, this code has been copied from the MS Blog, but keep a note of it .. we will be modifying this too in Part 3!

So .. we have our XML schema, and we have our JS file created, but we haven’t actually DONE anything with them yet.

So lets create a method to register our new Contextual Tab:

private void AddContextualTab()
        {
            //Gets the current instance of the ribbon on the page.
            Microsoft.Web.CommandUI.Ribbon ribbon = SPRibbon.GetCurrent(this.Page);
            //Prepares an XmlDocument object used to load the ribbon extensions.
            XmlDocument ribbonExtensions = new XmlDocument();
            //Load the contextual tab XML and register the ribbon extension.
            ribbonExtensions.LoadXml(this.contextualTab);
            ribbon.RegisterDataExtension(ribbonExtensions.FirstChild, “Ribbon.ContextualTabs._children”);
            //Load the custom templates and register the ribbon extension.
            ribbonExtensions.LoadXml(this.contextualTabTemplate);
            ribbon.RegisterDataExtension(ribbonExtensions.FirstChild, “Ribbon.Templates._children”);
        }

So .. this method is basically using the SPRibbon object to get a reference to the Ribbon on the current page. It is then loading in our XML schema to register a new contextual tab).
(Eventually we will end up calling this method from the PreRender() event).

Now we are going to need to register our JavaScript, and strangely enough we are going to do that with yet more JavaScript! (yes .. when you are working with the Ribbon JavaScript really is word of the day!)

public string DelayScript
        {
            get
            {
            string webPartPageComponentId = SPRibbon.GetWebPartPageComponentId(this);
            return @”
            <script type=””text/javascript””>
            //<![CDATA[
            function _addCustomPageComponent()
            {
                var _customPageComponent = new ContextualTabWebPart.CustomPageComponent(‘” + webPartPageComponentId + @”‘);
                SP.Ribbon.PageManager.get_instance().addPageComponent(_customPageComponent);
            }
            function _registerCustomPageComponent()
            {
                SP.SOD.registerSod(“”CustomContextualTabPageComponent.js””, “”\/_layouts\/CustomContextualTabPageComponent.js””);
                SP.SOD.executeFunc(“”CustomContextualTabPageComponent.js””, “”ContextualWebPart.CustomPageComponent””, _addCustomPageComponent);
            }
            SP.SOD.executeOrDelayUntilScriptLoaded(_registerCustomPageComponent, “”sp.ribbon.js””);
            //]]>
            </script>”;
            }
        }

The really important part of this is the first line:

SPRibbon.GetWebPartPageComponentId(this);

This gets a unique reference for the instance of your Web Part, on the current page, in the context of the Ribbon. This is used to effectively identify your Web Part when someone clicks on it!
The other really important bit is the last line:

SP.SOD.executeOrDelayUntilScriptLoaded(_registerCustomPageComponent, “”sp.ribbon.js””);

This is the new “Script On Demand” (SOD) method which allows us to tell SharePoint not to try loading our JavaScript until the SP.Ribbon.JS has already been processed!
Once that has been done we need to implement our WebPartContextualInfo method:

public WebPartContextualInfo WebPartContextualInfo
        {
            get
            {
                // create objects for the contextual web part tab
                WebPartContextualInfo info = new WebPartContextualInfo();
                WebPartRibbonContextualGroup contextualGroup = new WebPartRibbonContextualGroup();
                WebPartRibbonTab ribbonTab = new WebPartRibbonTab();
                //Create the contextual group object and initialize its values.
                contextualGroup.Id = “Ribbon.CustomContextualTabGroup”;
                contextualGroup.Command = “CustomContextualTab.EnableContextualGroup”;
                contextualGroup.VisibilityContext = “CustomContextualTab.CustomVisibilityContext”;
                //Create the tab object and initialize its values.
                ribbonTab.Id = “Ribbon.CustomTabExample”;
                ribbonTab.VisibilityContext = “CustomContextualTab.CustomVisibilityContext”;
                //Add the contextual group and tab to the WebPartContextualInfo.
                info.ContextualGroups.Add(contextualGroup);
                info.Tabs.Add(ribbonTab);
                // fetch dynamic component info for the current page’s Ribbon control
                info.PageComponentId = SPRibbon.GetWebPartPageComponentId(this);
                return info;
            }
        }

Now lets take a quick look through some of this code first. The first thing you should notice is that there are 3 new classes provided in the OOB API specifically for providing contextual tabs (from Web Parts):

  • WebPartContextualInfo
  • WebPartRibbonContextualGroup
  • WebPartRibbonTab

These objects contains all of the core functionality that you will need to handle the interaction between selecting your Web Part in edit mode, and the Ribbon dynamically popping up your Tab when that happens.
The RibbonContextualGroup and RibbonTab objects then get given both an ID property and a VisibilityContext. These values refer to the same pointers in the XML schema definition for the Tab, Group and Controls that we are going to register (which we created earlier).
The final part of the puzzle is to add these to the Web Part’s load stack (in this case, the Pre-Render method):

protected override void OnPreRender(EventArgs e)
{
            base.OnPreRender(e);
            this.AddContextualTab();
            ClientScriptManager clientScript = this.Page.ClientScript;
            clientScript.RegisterClientScriptBlock(this.GetType(), “ContextualTabWebPart”, this.DelayScript);
}

So, we are registering our contextual tab (using the AddContextualTab method we created earlier).
We then dynamically add a “lazy load” reference to our “DelayScript” string, which will register all of the JavaScript functions that we are using.

Build / Deploy / Test
There you have it … a contextual tab in edit mode!

Make sure you check back for:

  • RCWP Part 3 – Edit Web Part using a Ribbon modal dialog
  • (Full source code for the solution will be published in Part 3)

    RCWP Part 1 – SPRetreat and the Related Content Web Part

    I’m sat on the train after a great day of SPRetreat (followed by SharePint of course!), superbly organised by Andrew Woodward (21Apps) and Ben Robb (CScape). It was a really good day of innovative ideas, problem solving, chewing the fat (and the occasional dirty joke… you know who you are!).

    The core challenge thrown down for the day involved trying to provide cross-site (collection) “related information”, effectively a “cross-pollination” function, using SharePoint 2010. There were some great ideas and a lot of top effort into involving the Managed Metadata Service, Custom Search API work and some cracking Scrum / Agile design processes.

    We had 5 sessions of 1 hour each, and my efforts for the day mostly revolved around delivering a “Related Content Web Part”, which could use Search to show other content from any data source which is in some way related to the information on the current page.

    In this post I’m going to walk through how my efforts of the day culminated in the “Related Content Web Part” but ended up being a generic “Dynamic Field Driven Search” web part, basically allowing a set of search results to be displayed based on the value of a field that is stored in the publishing page (i.e. content type) that contains the web part (which derived from the Search CoreResultsWebPart).

    In the final sessions we though about how to improve this, and ended up building a custom contextual ribbon interface to surface SP Modal Dialogs to allow easy updating of core web part properties.
    Core Functionality

    The functionality is really split into 3 major sections:

    (Full source code for the solution will be published in Part 3)

    RCWP Part 1 – Extending the Core Results Web Part
    This is one of the nicest new “features” of SharePoint 2010. They have stopped sealing all of the Web Parts (and Web Part Connections)that are used for the results pages in SharePoint Search solutions. This means it is now much easier for you to extend and add-value to these web parts without having to throw out all of the OOB functionality.
    The reason for using the CoreResultsWebPart was simple;

    • Using search is fast, efficient, cross farm and highly configurable.
    • The core results web part using XSLT for rendering, so easy to design the output.
    • Leveraging an OOB web part means we get loads of added functionality for free! (like specifying which scope we want to use).

    In this solution, we extended the CoreResultsWebPart to create our own Web Part. Simple create a new Visual Studio 2010 “Web Part” item and set it to inherit from “CoreResultsWebPart” (you will need to add a reference to Microsoft.Office.Server.Search.dll).

    [ToolboxItemAttribute(false)]
    public class RelatedContentWebPart : CoreResultsWebPart
    {
    }

    In terms of functionality we need to do 1 thing:

    Override the Query programmatically, based on the metadata of the current page.

    This involved a few steps. First off, we need to identify which field we want to be “targeting”. For this we created a simple string field, exposed as a Web Part Property.

    private string fieldName = “Title”;
    ///<summary>
    /// The field on the current page we want to use for filtering
    ///</summary>
    [WebBrowsable(true)]
    [Personalizable(PersonalizationScope.Shared)]
    [WebDisplayName(“Field Name”)]
    [SPWebCategoryName(“Filter SPR”)]
    [WebPartStorage(Storage.Shared)]
    [Description(“Which field on the current page do you want to use for filtering?”)]
    public string FieldName
    { get { return fieldName; } set { fieldName = value; } }

    Then we needed to override the query itself. This is simply done by setting the “FixedQuery” property of the CoreResultsWebPart. The trick here is you need to set this in the “OnInit” event, otherwise it won’t take effect (if you try to place it in OnLoad, CreateChildControls or any other later method then it won’t have any effect!).

    protected override void OnInit(EventArgs e)
    {
        this.FixedQuery = “keyword string value”;
        base.OnInit(e);
    }

    Finally, we need to make sure we are pulling out the field value of the current list item, based on our custom field. For this we used a simple set of SPContext combined with some defensive programming to make sure we don’t get any NullReferenceException errors. So change the “OnInit” event to the following:

    protected override void OnInit(EventArgs e)
    {
        if (!string.IsNullOrEmpty(fieldName))
        {
            if(SPContext.Current.ListItem.Fields.
                ContainsFieldWithStaticName(fieldName))
            {
                this.FixedQuery =
                    SPContext.Current.ListItem[fieldName].ToString();
            }
        }
        base.OnInit(e);
    }

    After that … Build / Deploy and the web part was working!

    The code could obviously be re-factored a little bit, but on the whole it’s all working 🙂
    Make sure you check back for:

  • RCWP Part 2 – Web Part with Ribbon Contextual-Tab
  • RCWP Part 3 – Edit Web Part using a Ribbon modal dialog
  • (Full source code for the solution will be published in Part 3)

    How to use LINQ for SharePoint in Anonymous mode

    Disclaimer – This has not been extensively tested, so please use the sample below at your own risk!
    I am a really big fan of using LINQ to SharePoint. It cuts out all of the nasty CAML and you can do very complex queries with only a few lines of code. The one big let-down was not being able to use LINQ to SharePoint in Anonymous mode… or so I thought!
    I actually stumbled across a blog post from Joe Unfiltered on getting LINQ to SharePoint working anonymously, so all the credit goes to him for finding this little gem.
    Basically, the problem is with the SPServerDataConnection object. If you crack this baby open with Reflector then you’ll see it relies on SPContext.Current for it’s operations. As the objects it calls are off-limits for anonymous users it forces an authentication prompt!
    There is, however, a simple way around this (a technique very similar to one I’ve used before when running with elevated privileges back to the Central Admin SPSite).
    You basically do the following:

    1. Take backup copy of the HttpContext.Current object
    2. Set HttpContext.Current = null;
    3. Execute your LINQ to SharePoint query
    4. Restore HttpContext.Current to it’s original (backup) value

    When the SPServerDataConnection object is created, as the SPContext.Current is null it will go ahead and instantiate a new object using the URL you passed through in your DataContext object 🙂
    Important – Don’t forget to put the HttpContext.Current back again after you have finished your LINQ query. This is VERY important, otherwise things will very quickly start to break!
    Sample code is below. Do Enjoy! (and thanks to Joe!)


    // store a copy of our current Context’s Web URL
    string strWebUrl = SPContext.Current.Web.Url;

    bool nullUser = false;

    try
    {
    // check if we are running anonymously (i.e. nullUser = true)
    nullUser = (SPContext.Current != null && SPContext.Current.Web.CurrentUser == null);

    // take a backup copy of the HttpContext.Current object
    HttpContext backupCtx = HttpContext.Current;

    if (nullUser)
    {
       // if running anonymously, set the current HttpContext to null
       HttpContext.Current = null;
    }

    // instantiate our data context (using the URL)
    MyCustomDataContext thisSite = new MyCustomDataContext (strWebUrl);

    // disable tracking to improve read-only performance
    eventSite.ObjectTrackingEnabled = false;


    // create a list of items from my custom list
    EntityList<Item> listItems =
         thisSite.GetList<Item>(“MyCustomList”);
    // query the list, only selecting items which meet the filter
    var currentItems = from listItem in listItems
       where listItem.Title != “”
       select listItem;

    // TODO: process your items
    }
    finally
    {
       if (nullUser)
       {
       // don’t forget to put your HttpContext back again
       HttpContext.Current = backupCtx;

       }
    }

    Update – Following this post (and the subsequent discussion on Twitter) there is a lot of questions around performance (creating new SPSite / SPWeb objects for each query) and the validity of nulling the HttpContext.Current in the first place.

    My original statement stands .. use this at your own risk, I haven’t fully tested it! 🙂 If you do your performance benchmarking and you are happy with it then no problem!

    SharePoint 2010 ALM – Part 2 – Upgrading your Solutions, In-Place or Side-by-Side?

    So in Part 1 we talked about some of the upgrade mechanisms available in SharePoint 2010, including Assembly level and Feature level versioning.

    In Part 2 we are going to look at 2 distinct versioning strategies:

    • In Place Upgrade (replace old with new)
    • Side-by-Side Release (allow both version to run at the same time)

    In-Place Upgrade

    This is going to be most common scenario for bug fixing, hotfixes and minor improvements to the solution. So you might be adding some help files, or tweaking a user interface, or perhaps fixing some JavaScript or CSS bugs in your code.

    Typically you would not use this approach for major versions of products, as a major change to interface or functionality is likely to confuse existing users, and might causing existing configurations to break! There are exceptions however, your client might not want to manually swap out 500 web-parts on their portal and might want a “big bang”.. provided it has been thoroughly tested!

    So what did we discuss in Part 1 that can be used in SharePoint 2010 to achieve an In-Place Upgrade?

    $SharePoint.Project.AssemblyFullName$

    This can allow you to easily update all of your ASCX / ASPX / CAML references with the new assembly.

    Next time your Page / Web Control / Feature receiver tries to execute then it will be running the new code, seamlessly.

    Assembly Binding Redirects

    This allows you to pick up any code that is attempting to execute in the old version, and forces it to run through the new assembly methods instead.

    This is a blanket, assembly-wide approach, typically deployed at the Web Application level (although you can go server-wide using the machine.config!)

    Warning – This obviously only works from code that runs through the web.config and IIS / ASP.Net. Any other code (such as Timer Jobs and Workflows) will be completely unaware of these redirects and will happily continue running the old code!

    Workflows especially should not use binding redirects this way. If you drop in a redirect for a workflow that is currently running then you will break it next time it tries to serialize itself to the database!

    Feature Versions

    The feature framework allows you to do incremental upgrade steps to modify existing features, upgrading and “replacing” the functionality for existing items (such as Content Types, site columns, custom actions … anything that you would provision through a Feature.xml).

    You might have to be careful with custom code (and the CustomUpgradeAction element) but all in all, Feature versions are designed to do an “in place upgrade” of your features.

    Side-by-Side Release

    This is likely to be the most common scenario for Major Versions, functionality changes, new templates. It is important to recognise that certain elements in the SharePoint schema MUST be upgraded in this way (such as Site Definitions, List Definitions and Workflows).  For this scenario “upgrade” is probably the wrong word to use, because what we really have to do is create a copy (and in some scenarios hide the old one!).

    So how would you go about creating a side-by-side upgrade? Well, the first thing to consider is that you need to leave your existing assembly in place.

    Solution Package (WSP) Considerations

    If you “retract” the solution package then typically it will remove your original DLLs. This will cause existing functionality to break (this is bad).

    One workaround is to create a new WSP. SharePoint will treat this as a separate solution, allowing you to install it while leaving the existing one in place.

    Assembly (DLL) and Package (WSP) Considerations

    The assembly needs careful consideration, depending on where your assembly is going to live;

    If you have a full trust package which deploys to the GAC, then you really don’t have too much of a problem. You can create your new assembly with a different version number and deploy that DLL to the GAC. The GAC has been designed that the same assembly with multiple version numbers can happily sit side-by-side.

    If you have a minimal trust package which deploys to the web application BIN folder then you have more of a problem. Releasing the same assembly name is going to overwrite the file (deleting the original DLL, which will break existing functionality … also bad). Other than moving it to the GAC (which breaks the whole point of deploying for minimal trust in the first place!) there is only one practical workaround here; rename your assembly (so you have 2 different DLL file names)

    So now that you have dealt with your assembly, what about other assets?

    Workflows (WWF)

    Workflows are a nasty one. One they are running the class gets serialized into the database, so you HAVE to leave existing code on the system until all instances of that workflow have stopped running! (you can set a workflow to “no more instances” from the remove screen). The problem is that in a typical environment you are probably going to have NO IDEA how many workflow instances are running (and even if you did, you probably won’t be able, or willing, to stop them!).

    The only scenario is to provide a duplicate workflow. Copy the workflow in Visual Studio, make your changes, and provision it into SharePoint as a DIFFERENT workflow.

    Again, you would hide the original (so people can’t add them to new lists) and you would probably want to perform some kind of exercise to remove any existing workflows (once all the running instances have stopped) and setup the new workflow as a new instance on the list / content type.

    As you can imagine, this is NOT going to be an easy task and it’s highly likely that this will be a manual governance effort, and not something that can be easily automated.

    (note – even if you are leaving the existing workflow class in place you still can’t change the assembly version … the serialization will fail and existing workflow instances will break!)

    Site Definitions (onet.xml)

    Microsoft very clearly states that modifying a Site Definition while it is use is not supported.

    So how DO you “upgrade” them? Well, you have 2 options:

    Feature Stapling

    The easy solution is to use a feature stapler to add new functionality to an existing site.

    This allows you to modify NEW sites that are created, although you won’t be able to impact on everything (features activate before lists and pages are created, so you won’t be able to modify those!)

    This is discussed in detail on MSDN: https://msdn.microsoft.com/en-us/library/bb861862(office.12).aspx

    Copy and Hide the Original

    This is pretty straightforward. You copy your Site Template folder and create a new version.

    You then modify your WEBTEMP*.xml file to add in your new template (using the same name / description as the original).

    You then set the original template in the WEBTEMP*.xml as Hidden=TRUE.

    Deploying this, your users still “see” exactly the same when they create new sites, but when they do create the site it is now provisioning using your new template!

    List Definitions (schema.xml)

    This is a very similar story to Site Definitions. You can change “some” things but not everything (and some of the things you change may break existing lists!).

    The most reliable way is to copy your Feature (giving it a new GUID) and hide the original ListTemplate. This will stop users from using the old template to create new lists, but if you have existing sites that are provisioning them automatically then you’ll have to look at the Site Definition upgrade (see above!).

    That should give you a pretty good grounding (at the very least a start!) at how to upgrade your projects, either in-place upgrade or side-by-side upgrade.

    A lot of it is going to be head-scratching and sitting down to think .. don’t rush into it, take your time, and make sure you truly understand what you are trying to achieve, and what the impact is going to be on the end users!

    SharePoint 2010 ALM – Part 1 – Versioning Features and Assemblies

    This post was prompted by needing to explain the versioning and upgrade strategy in SharePoint 2010 to some partners we are working with at Content and Code. It ended up a very length conversation so I decided to jot it all down and split it up into 2 parts.

    • Part 1 – Feature and Assembly Versioning
    • Part 2 – Upgrading your projects for In-Place Upgrade or Side-by-Side release.

    Regarding upgrading SharePoint 2010 projects there are 2 specific areas of new functionality that will key for SharePoint 2010 Application Lifecycle Management:

    • Assembly Versions
    • Feature Versions

    Assembly Versions

    It is typically recommended that the Assembly Version is incremented when you are upgrading / fixing / changing any of your managed code. This will however have an implication for web parts, web controls and pages across the system, but SharePoint 2010 has provisioned for that.

    $SharePoint.Project.AssemblyFullName$

    This is a new placeholder value that you will find all over SharePoint 2010. This includes both ASPX / ASCX  files (such as Page Layouts or Visual Web Parts, as an <% @Assembly %> tag) as well as Feature Receivers (in the Feature XML). Basically, when you package your WSP SharePoint will automatically swap out this value for the fully-qualified Assembly Reference for the current project state. This means it will swap out the full Assembly name, version number, culture and Public Key Token.

    Assembly BindingRedirect element (solution manifest.xml)

    Another new feature in SharePoint 2010 is the ability to specify an AssemblyBindingRedirect from the WSP.

    This is part of the Manifest.xml schema (and has intellisense support in Visual Studio 2010) to allow you to automatically add new assembling binding information when a new WSP is rolled out.

    Example: binding redirect to redirect version “1.0.0.0” to the current assembly version in the package:

    <Assemblies>

        <Assembly Location="MyCustomAssembly.dll" DeploymentTarget="GlobalAssemblyCache">

          <BindingRedirects>

            <BindingRedirect OldVersion="1.0.0.0"/>

          </BindingRedirects>

        </Assembly>

    </Assemblies>

    With these two functions combined, we should have no problem upgrading an existing assembly to a new version.

    You should be aware though that the Binding Redirects will only apply to the Web Application’s web.config, and therefore will NOT work for anything operating outside of the web context (such as Timer Jobs and Workflows!). This is discussed in more detail in Part 2.

    Feature Versions

    There are a number of new version-related parts to the Feature framework. Each feature.xml can now be given a specific Version number property (if you don’t specify then it will be given a value of 0.0.0.0). This property was listed in the WSS 3.0 SDK, but it was reserved for internal use at the time (now it finally gets some legs!)

    This all stems from a new set of XML elements that you can add to the Feature.xml, starting with <UpgradeActions> element.

    <VersionRange>

    The first element is the Version Range .. which allows you to specify the BeginVersion and EndVersion. The actions specified in the upgrade will only be processed if the if the current version of the feature is between that range!

    Typically you would wrap this element around the actions that you wish to be executed when the upgrade is performed.

    <AddContentTypeField>

    Pretty much as it says on the tin, this allows you to add a field to an existing Content Type.

    <ApplyElementManifests>

    This allows you to apply a specific element manifest when the upgrade process kicks off.

    This is good because if you are adding a new element manifest (say to provision a new site column?) then you can process that specific manifest in isolation as part of your upgrade process without going off and executing all of the other manifests in the feature.

    <MapFile>

    According to the SDK this allows you to re-map a file in the content database to a different “ghosted” location. I suppose this is a supposed to be a quick, memory efficient way of gracefully modifying files, although I’m not sure what value this really has? (could you not just overwrite the file on the hard disk?)

    <CustomUpgradeAction>

    This element ties in with your Feature Receivers. There is a new method in the SPFeatureReceiver class. This method is called: FeatureUpgrading() and it allows you to execute custom code as part of your upgrade process.

    (the only problem is that .. if you deploy your feature to a brand new farm and execute it “first time” from the new version .. this method does not get executed! You should really consider using the Feature Activated event to make sure it the behaviour is consistent!)

    Example:

    Below is an example snippet.

    Here, if we are upgrading from Version 1 to Version 2 then a new field will be added to a content type, and those changes pushed down to all child content types and lists.

    If we are upgrading from Version 2 to Version 3 then a new element manifest will be processed.

    <UpgradeActions>

        <VersionRange BeginVersion="1.0.0.0" EndVersion="2.0.0.0">

          <AddContentTypeField

    ContentTypeId="0x010100C568DB52D9D0A14D9B2FDCC96666E9F2007948130EC3DB064584E219954237AF39"

    FieldId="{C6885FF1-4F70-425F-AB32-41767AB1B8CC}"

    PushDown="TRUE"/>

        </VersionRange>

        <VersionRange

            BeginVersion="2.0.0.0"

            EndVersion="3.0.0.0">

          <ApplyElementManifests>

            <ElementManifest Location="UpgradeManifest.xml"/>

          </ApplyElementManifests>

        </VersionRange>

      </UpgradeActions>

    With the feature upgrade framework, this should allow you to do almost anything when managing how your features are “upgraded” in a graceful way.

     

    In Part 2 we will discuss how we can leverage these for two different upgrade scenarios:

    • In-Place Upgrade (replacing existing functionality)
    • Side-by-Side Installation (allowing two versions to co-exist)

    SP2010 RTM Bug found in CQWP [PageQueryString] feature

    Sigh .. another few days of RTM development and another bug found …

    This one regards the Content by Query Web Part (CQWP) and the new PageQueryString filter functionality. This is a cracking new feature which allows you to dynamically set the filter based on a query string value in the request URL… unfortunately there is a bug.

    I found this when I was trying to set an aggregation of some News pages, but filter them using a query string as a poor-man’s web part connection 🙂

    My Requirement: Show all custom “News” pages within the pages library of my News site, and filter the date using a query string value.

    Normally this would involve custom development, but not any more in SharePoint 2010!

    1. I targetted my CQWP at the Pages Library (no point querying the entire site, as it would be a performance hit).
    2. I also targetted the CQWP at my custom “News Page” content type, as I didn’t want the “home” page to be returned in the aggregation
    3. Finally, I added a Filter of “Article Date” is Greater Than [PageQueryString: StartDate], so that I can start to filter my news by date using the query string.

    I hit the “apply” button with sweaty palms .. excited to see this new functionality in action ..

    There is a problem with the query that this Web Part is issuing. Check the configuration of this Web Part and try again.

    FAIL

    What Went Wrong?
    This was quite a shock .. I checked and double checked that my filters were setup correctly.. I spent an entire day checking and double checking all of my settings and values to make sure I hadn’t made a mistake somwhere. If I removed that filter then it worked (and returned all my news items). Bizarelly if I included a valid query string like ?Title=Home in my URL then it WORKED?? But remove the filter completely and it failed …

    So What EXACTLY doesn’t work ??
    I spent a good few hours investigating this in more detail, and came across the following findings. If you have the following ALL set in your CQWP then it will fail:

    • Targetting a Specific List, and
    • Targetting a specific Content Type, and
    • Any [PageQueryString] filter in your query, and
    • The [PageQueryString] variable is NOT present in the URL

    If you change any one of these settings then it will start working!

    How To Replicate This Bug
    This is quite simple really, just follow these steps:

    1. Create a new “Publishing Site” site collection
    2. On the home page, add a new Content By Query Web Part
    3. Set the following query properties
      • Show items from the following list: /Pages
      • Show items of this content type group: Publishing Content Types
      • Show items of this content type: Page
      • Show items when: Title > Contains > [PageQueryString: title]

    4. Hit Apply. The web part will report: There is a problem with the query that this Web Part is issuing. Check the configuration of this Web Part and try again. If you add ?Title=Home to the query string then you should notice that the web part appears to work, but fails if the query string property is missing!

    What is the Workaround?

    If you then do ANY of the following, it will work:

    • Point it at a Site, or Site Collection, instead of a specific list, or
    • Do not filter by Content Type, or
    • Do not use a [PageQueryString] filter

    Now … for my example (bring up pages using a specific page layouts from a pages library) I chose to change the query to target the site. I don’t have a lot of other content in my News site, so it won’t be much of a problem.

    I can imagine this cropping up again and again in the future though, especially with large Intranet sites with thousands (or even millions?) of documents … you don’t want to be doing site-wide queries there, the performance impact would be significant!!

    Update:
    Glyn Clough has come up with a workaround. It seems that adding an additional filter that is always true (such as Title != “”) makes it work. Annoying, but at least there is a workaround.

    VS 2010 RTM and SP 2010 RTM – Deployment Conflict Resolution will break modules!

    What a way to lose 4 hours of your life.

    I was in a glorious mood this morning having upgraded my main development environment to RTM (both SharePoint 2010 and Visual Studio 2010 (Premium)).

    The main code base we’d been working on (a brand new SP2010 web site, due to go live next month) compiled, the packaged could be created and I manually deployed the WSP and all was good … that is until I tried the “Deploy” button in Visual Studio…

    Error Occurred in deployment step ‘Add Solution’: Value cannot be null. Parameter name: s

    FAIL

    So what on earth could be causing this error? Well, I stumbled across a registry edit that enabled diagnostics logging for SharePoint projects in VS 2010 (thanks to Glyn Clough for letting me know about it).

    Enable Diagnostics Logging for SharePoint Projects in Visual Studio 2010
    [HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\10.0\SharePointTools] “EnableDiagnostics”=dword:00000001

    This gave me a stack trace in the Output window for the build alongside the error message, as follows:

    (I have highlighted the error message, as well as the line throwing it .. the StringReader constructor complaining that it’s been passed a null value!)

    —— Build started: Project: MySharePointProject, Configuration: Debug Any CPU ——

    MySharePointProject -> C:\Projects\MySharePointProject\bin\Debug\MySharePointProject.dll
    Successfully created package at: C:\Projects\MySharePointProject\bin\Debug\MySharePointProject.wsp

    —— Deploy started: Project: MySharePointProject, Configuration: Debug Any CPU ——
    Active Deployment Configuration: Default
    Run Pre-Deployment Command:
    Skipping deployment step because a pre-deployment command is not specified.
    Recycle IIS Application Pool:
    Skipping application pool recycle because no matching package on the server was found.
    Retract Solution:
    Skipping package retraction because no matching package on the server was found.
    Add Solution:
    Error occurred in deployment step ‘Add Solution’: Value cannot be null.
    Parameter name: s

    Exception Message: Value cannot be null.
    Parameter name: s
    Exception Type Name: System.ArgumentNullException

    Exception Stack Trace: at System.IO.StringReader..ctor(String s)
    at System.Xml.Linq.XDocument.Parse(String text, LoadOptions options)
    at Microsoft.VisualStudio.SharePoint.ProjectExtensions.VSPackage.XmlDocument.GetXDocument()
    at Microsoft.VisualStudio.SharePoint.ProjectExtensions.VSPackage.XmlDocument.get_Document()
    at Microsoft.VisualStudio.SharePoint.ProjectExtensions.VSPackage.ModuleElementManifest.GetModuleElements(Boolean ignoreSetupPathModules)
    at Microsoft.VisualStudio.SharePoint.ProjectExtensions.VSPackage.ModuleElementManifest.GetFileElements(Boolean ignoreSetupPathModules)
    at Microsoft.VisualStudio.SharePoint.ProjectExtensions.VSPackage.ModuleCollisionFinder.b__2(ISharePointProjectItemFile elementManifest)
    at System.Linq.Enumerable.d__31`3.MoveNext()
    at System.Linq.Buffer`1..ctor(IEnumerable`1 source)
    at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
    at Microsoft.VisualStudio.SharePoint.ProjectExtensions.VSPackage.SingleAspectCollisionFinder`1.FindConflicts()
    at Microsoft.VisualStudio.SharePoint.ProjectExtensions.VSPackage.DeploymentConflictFinder.FindAndAddConflictsTo(IDeploymentConflictCollection targetConflictCollection, Boolean promptBeforeResolve)
    at Microsoft.VisualStudio.SharePoint.ProjectExtensions.VSPackage.Module.DetectConflicts(DeploymentStepStartedEventArgs e, Boolean promptBeforeResolve)
    at Microsoft.VisualStudio.SharePoint.ProjectExtensions.VSPackage.Module.DeploymentStepStarted(Object sender, DeploymentStepStartedEventArgs e)
    at Microsoft.VisualStudio.SharePoint.SharePointProjectItemTypeEvents.RaiseDeploymentEvent[T](EventHandler`1 eventHandler, T e, ISharePointProjectItem projectItem, ISharePointProjectItemDeploymentContext context)
    at Microsoft.VisualStudio.SharePoint.SharePointProjectItemTypeEvents.OnDeploymentStepStarted(ISharePointProjectItem projectItem, IDeploymentStepInfo stepInfo, ISharePointProjectItemDeploymentContext context, IDeploymentConflictCollection conflicts)
    at Microsoft.VisualStudio.SharePoint.SharePointProjectItemType.OnDeploymentStepStarted(ISharePointProjectItem projectItem, IDeploymentStepInfo stepInfo, ISharePointProjectItemDeploymentContext context, IDeploymentConflictCollection conflicts)
    at Microsoft.VisualStudio.SharePoint.Deployment.DeploymentUtils.NotifyStepStarted(IDeploymentStepInfo stepInfo, IDeploymentContext context)
    at Microsoft.VisualStudio.SharePoint.Deployment.ConfigurationExecutor.Execute()
    at Microsoft.VisualStudio.SharePoint.Deployment.WspDeploymenHandler.Deploy()
    ========== Build: 1 succeeded or up-to-date, 0 failed, 0 skipped ==========
    ========== Deploy: 0 succeeded, 1 failed, 0 skipped ==========

    So .. what does this tell us?

    Firstly, all of the exceptions are being thrown by internal Microsoft assemblies. There is no custom code, no custom solutions and no 3rd party bolt ons. But the thing that didn’t jump out at me straight away was buried in the middle of the stack trace … a load of references to “conflicts”:

    • VSPackage.Module.DetectConflicts
    • VSPackage.DeploymentConflictFinder.FindAndAddConflictsTo
    • VSPackage.SingleAspectCollisionFinder`1.FindConflicts
    • VSPackage.ModuleCollisionFinder

    This sparked inspiration… there is an option in Visual Studio 2010 to set Deployment Conflict Resolution on a module that you have added. Deployment Conflic Resolution will automatically check for files that you are deploying to see if they already exist. If they are outdated then Visual Studio can forcibly delete them and upload the newer versions (quite a nice feature .. when it works).

    By default this value is set to “Automatic” .. so I tried turning it off and set it to “None“.
    SUCCESS
    The build now works with Deployment Conflict Resolution disabled!
    It’s a shame that I can’t get my solutions to deploy without that turned off. It would be nice to have conflict resolution enabled on my projects, but at the moment this is the only way I can get them to work.
    Why has this happened? My only real guess is that Visual Studio 2010 RTM came out several weeks before SharePoint 2010 RTM, so perhaps somewhere the conflict resolution code got out of sync with the latest SharePoint release?? (that is a very wild guess / stab in the dark ..)
    Also please bear in mind that this is using SharePoint 2010 RTM and Visual Studio 2010 Premium (RTM). I have noticed this with both brand new OOB projects and existing projects, so be careful when migrating your code base from an RC based dev environment to RTM!
    The original MSDN post where I reported (and quite quickly solved myself) can be found here:
    If there is a hotfix or patch released I’ll make sure both places get updated!
    Thanks for listening … another 4 hours of my life gone forever, but hey .. what doesn’t kill you only makes you stronger right??
    « Older Entries Recent Entries »