Feeds:
Posts
Comments

Archive for the ‘SharePoint 2010’ Category

As SharePoint Developers, we are often challenged with requests to sort list item data seemingly arbitrarily. In these cases, none of the field data can be used to sort ascending or descending and get the results we are seeking. Often, we end up creating a Number column and setting a value so we can sort on that value. The trouble here is that you must manually update all of the other items. This can be painful if you’re trying to move an item with Order = 50 to Order = 1: You must change the Order value on 49 other items!

Links Lists have a handy link in the Items menu labelled “Change Item Order.” The page this link takes you to allows you to change the order of items in the Links List just like you would change the order of fields in a list view. SharePoint then stores the numerical sort order in a hidden field on the list which the Links Lists view uses with an orderBy.

So, excellent, there is something out of box to do what we want to do. Hooray! Now, how do we make use of it? Turns out, if you add a column to your custom list that is identical to the hidden column used in the Links List, you can take advantage of the “Change Item Order” page for your custom list! Here’s how I did it:

Using SharePoint REST API, I discovered the SchemaXml property for the hidden Order field in the Links List is:

<Field ID=\"{ca4addac-796f-4b23-b093-d2a3f65c0774}\" ColName=\"tp_ItemOrder\" RowOrdinal=\"0\" Name=\"Order\" DisplayName=\"Order\" Type=\"Number\" Hidden=\"TRUE\" SourceID=\"http://schemas.microsoft.com/sharepoint/v3\" StaticName=\"Order\" FromBaseType=\"TRUE\" />

I then simply generated a POST using the REST API once again to create a field on my custom list using the SchemaXml above. You can, of course, use whatever app you wish to do the POST. My favorite is Postman. Here’s how I setup the request to send:

  1. POST to [your site URL]/_api/web/lists/getbytitle(‘[title of your custom list]‘)/fields/createfieldasxml
  2. Headers:
    1. Accept: application/json
    2. Content-Type: application/json
    3. X-RequestDigest: [a current request digest]
  3. Body:
    {
        "parameters": {
           "__metadata": {
              "type": "SP.XmlSchemaFieldCreationInformation"
           },
           "SchemaXml": "&lt;Field ID=\"{ca4addac-796f-4b23-b093-d2a3f65c0774}\" ColName=\"tp_ItemOrder\" RowOrdinal=\"0\" Name=\"Order\" DisplayName=\"Order\" Type=\"Number\" Hidden=\"TRUE\" SourceID=\"http://schemas.microsoft.com/sharepoint/v3\" StaticName=\"Order\" FromBaseType=\"TRUE\" /&gt;"
        }
    }

This adds a hidden Order field to your custom list. The only thing left to do is access the “Change Item Order” page for your list and start setting item order. Here’s the URL:

[your site URL]/_layouts/15/Reorder.aspx?List=[your list GUID]

If you want to get the ordering data for your client-side app, here’s an important tip: The SharePoint REST API does not return the Order field when you simply execute a call to _api/web/Lists…/items. If you add Order to a $select option—like _api/web/Lists…/items?$select=Order—the item ordering set by the “Change Item Order” page will be returned.

Happy ordering! Let me know below if you find any issues doing this.

Update/Note, 11/7/2017: The “Change Item Order” page only supports up to 100 items at a time. It pages items in groups of 100. Thus, it gets a little tricky to move an item around when you’re dealing with hundreds of items or more.

Advertisements

Read Full Post »

We resolved an issue today where a SharePoint Admin mistakenly deleted an out-of-the-box SharePoint Timer Job. Many of the “resolutions” we found while searching for a fix to the “uh oh!” involved the recreation or restoration of several–if not all–of the timer jobs which come with SharePoint. Honestly, that made me nervous because I’d rather not be touching something that is working just fine.

Knowing that custom timer jobs get attached through a few lines of code, I figured the same could probably be done to fix our single missing timer job. And, sure enough, it could! Here’s the PowerShell we used to restore the mistakenly deleted Information management policy job:

[System.Reflection.Assembly]::Load("Microsoft.Office.Policy, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c");
$wa = get-spwebapplication http://webappurl;
[Microsoft.SharePoint.SPSchedule] $schedule = [Microsoft.SharePoint.SPSchedule]::FromString("weekly at fri 23:00:00");
[Microsoft.Office.RecordsManagement.Internal.PolicyUpdatesJobDefinition] $policyJob = New-Object "Microsoft.Office.RecordsManagement.Internal.PolicyUpdatesJobDefinition" ($wa);
$policyJob.Schedule = $schedule;
$policyJob.Update($true);

To restore your mistakenly deleted job, all you need to do is find the assembly which contains the job (“Microsoft.Office.Policy” above) and the class used to instantiate the SPTimerJob (“Microsoft.Office.RecordsManagement.Internal.PolicyUpdatesJobDefinition” above). Substitute your assembly and class as needed above. Of course, you’ll want to use your web application URL instead of “webappurl.”

Mark Arend has a wonderful post on MSDN Blogs about the strings for SPSchedule.FromString.

Read Full Post »

Steve Peschka put together a great blog post about Bypassing the Multi Authentication Provider Selection Page in SharePoint 2010 that was also incorporated in a Microsoft MSDN article. (If you’re not concerned with SharePoint 2010 and are here for info regarding SharePoint 2013, skip down to the “SharePoint 2013” heading.) The workaround Peschka provides works, but I had a few issues with how it was put together:

  1. It’s not a solution deployment. Manual. 😐
  2. You’re replacing an out-of-the-box page. What happens to your changes if a CU updates that page? :-/
  3. The change affects all web applications ran on the WFE server you make the change on. What if you have a web application you don’t want to auto-select a provider?

My first issue was disappointing. My second issue was risky. My third issue? Just not acceptable because we do have multiple web applications and don’t want all of them to auto-select. (more…)

Read Full Post »

My thanks to Peter Holpar for his blog post on “How to Override the Default Item Save Event Using Custom Fields.” Gave me the information I needed to create a handy custom field.

During our testing, though, we found that save errors were not being handled correctly. For example, when the “Allow duplicate values” was set to “No” and you tried to set a duplicate value in the field, you got a very ugly error page. So, I went back to Peter’s blog: No solution. I searched all over: no solution. So, back to Peter’s blog. There was one little tidbit that turned into the key to solving the problem and getting SharePoint to properly handle the SPDuplicateValuesFoundException. Peter mentioned an alternative to using SPContext.Current.ListItem.Update() was to use SaveButton.SaveItem(). Close, very close! The parameterless method is actually not available to our custom field, but SaveButton.SaveItem(SPItemContext, bool, string) is. Calling this method instead of the update method took care of the problem. Now, when someone tries to enter a duplicate value in our custom field, we get the nice, red message “This value already exists in the list.”

Now a happy Monday morning!

Read Full Post »

Radu Tut did a wonderful blog about how to get Search Analytics Reports programmatically in SharePoint 2013. I am quite grateful for his guidance and it’s undoubtedly the most referenced article on the topic (even being referenced in Microsoft blogs and other documentation).

I followed Radu’s guidance and have successfully retrieved usage data from my site collections in 2013, but I’ve discovered a few things I’ve not seen anyone talking about:

  1. It is important to note that the DateTime value you use should be UTC. If not, you will, at some time during the day–depending on your offset–get a “Specified argument was out of the range of valid values” error when trying to get the furthest back data (example: -14 days for Day) if you use Local time. Internally, SharePoint uses DateTime.UtcNow.Date (see reflection of Microsoft.Office.Server.Search.Analytics.AnalyticsItemData in the Microsoft.Office.Server.Search.Applications.dll).
  2. To my surprise, I was able to retrieve usage data from a 2010 site collection in SP2013! Apparently, SharePoint is tracking and compiling this data, but the 2010 UI has no way to interface with the data. Thus, if you need usage data for a 2010 UI site collection in SharePoint 2013, turn to your Devs or PowerShell-savvy Admins: If your site is being crawled, the 2013 usage data you seek is in there!
  3. The time period for SP2013 to compile usage data is fairly lengthy (at least 15 minutes in my tiny dev farm). If you attempt to retrieve the data while SharePoint is compiling it, you’ll get back a big fat ‘0’. For expected results, make sure you’re not retrieving the data while SharePoint is compiling it. 🙂 I believe this compilation is done by a timer job once a day at midnight, by default (I was up pretty late working on my project when I discovered this behavior).

Happy reporting!

Read Full Post »

Sometimes, the old ways just work cleaner. After struggling for far longer than I should have to get files to post to my document library using the REST interface, I turned back the clock and looked at how I had done it in times past:

private static void PostFile(string url, byte[] bytes)
{
  HttpWebRequest r = (HttpWebRequest)WebRequest.Create(url);
  r.Credentials = CredentialCache.DefaultNetworkCredentials;
  r.Method = "PUT";
  byte[] buffer = new byte[1024];
  using (Stream stream = r.GetRequestStream())
  {
    using (MemoryStream ms = new MemoryStream(bytes))
    {
      for (int i = ms.Read(buffer, 0, buffer.Length); i > 0; i = ms.Read(buffer, 0, buffer.Length))
      {
        stream.Write(buffer, 0, i);
      }
    }
  }
  WebResponse resp = r.GetResponse();
  resp.Dispose();
}

The url parameter that you pass to this method is simply the URL the document will have after being posted. Example: http://sppaule/sites/test/Shared%20Documents/TestFolder/test.txt (this example would put the file “test.txt” in the TestFolder folder of the Shared Documents library in the “test” site). The bytes parameter contains the byte[] of the file to upload.

 
“More isn’t always better, Linus. Sometimes it’s just more.” (Anyone name that movie?)

 

Read Full Post »

Older Posts »