Jason Specland: Consultant, Comedian

Making it up as I go along. Always.

Category: SharePoint

Project Estimation for SharePoint: A Parable

EXT. OUTSIDE THE JUNGLE, DAY

An intrepid treasure hunter and his local guide stand trepidatiously outside of a dark, mysterious, wild jungle.

Treasure Hunter: How long will it take for us to get through the jungle?
Guide: It’s hard to say. The jungle is filled with dangerous traps and difficult terrain.
Treasure Hunter: Okay, how long will it take to get two miles through the jungle?
Guide: Seriously, it’s hard to say. I don’t know what we’re going to encounter…
Treasure Hunter: Just ballpark it for me.
Guide: Okay, well I’m really not certain, so I’m going to have to assume the worst… Three days?
Treasure Hunter: Three days!? To go two miles!? What are you, incompetent or something?
Guide: Okay, if everything goes absolutely perfectly… A day, maybe? But don’t hold me to that…

CUT TO: Two days later…

EXT. INSIDE A PIT TRAP IN THE MIDDLE OF THE JUNGLE, DAY

Treasure Hunter: We’re a day over budget. I’m not paying you for this, you know.

A Dog Named ‘Cat’: What Happens When You Name a SharePoint Field ‘DisplayName’?

Sometimes I feel bad for junior front-end developers who think they have a decent handle on things, and then get thrown into the world of SharePoint. They don’t have the SharePoint Spidey-sense that tells them something simple is going to go horribly wrong.

I was called on to assist a junior developer who was tearing his hair out trying to do simple CRUD operations on list items in SharePoint in an Angular application. I’d already written a (somewhat) simplifying Angular service to deal with most of the annoying parts of the REST API, so I was baffled that he was having so much trouble with it.

So I stepped into the code with him, making sure he was calling my service correctly. He was. I began to panic. Was there a bug in my service? I stepped into the service code. Everything looked fine, and SharePoint returned the proper “201 CREATED” response. But every field except one was being set.

The name of that field was “DisplayName”.

Curious.

I proceeded to create a new Custom List called “TestThisBug.” I created a field called “DisplayName” and another field called “FooDisplayName.”

sp2013-displayname-bug-in-interface

Simple, right? Then I tried to get the fields via the REST API.

sp2013-displayname-bug-in-rest

The field did not appear. Curiouser and curiouser.

I tweeted the tweet above, and told the developer to name the field something else and be on his way. I wondered, “What if we try the same operations using the JSOM?”

So, on my SharePoint 2013 VM, I fired up a Site Collection, created my list, and wrote me some JSOM code. I wrote some code that will get that list item, select a few fields (including “DisplayName”) and just display it in a table.

sp2013-every-field-but-displayname

I got every field I asked for, except for “DisplayName” which was silently disregarded. When I tried to ask for it directly via get_item('DisplayName') I was told it wasn’t initialized, despite the fact that I’d explicitly requested it.

sp2013-uninitialized-property-jsom

I began to wonder if I would run into the same creation issue my coworker was encountering. I wrote some more JSOM code to actually create a list item with the “DisplayName” field set. And, even more strangely… It worked!

sp2013-succesfully-created-item-with-jsom

I then logged on to my Office 365 Dev Tenant to see if this is still an issue.

o365-displayname-bug-in-rest

o365-displayname-bug-with-jsom-added-item

Yup! Sure is! You can see here that I can get the field name from the list via list.get_fields(), but when I return list items, the field is not returned, despite explicitly requesting it. You can also see that the “DisplayName” field that is returned from get_fields() doesn’t have any super-secret internal name that I’m missing.

But, as before, adding a list item with that field via JSOM works just fine:

o365-displayname-bug-with-jsom-added-item

So, kids, I guess the moral of this story is pretty simple: Don’t name your fields “DisplayName.”

Here’s the bug-test JSOM code.

I’ve Seen the Future…

Well, by now every SharePoint person on Earth has seen and blogged about the #FutureOfSharePoint announcement. Most of the top SharePoint bloggers have just been sitting on all this until today, but I run in far humbler circles.

So let’s look at what I wanted, and what I got:

A Master Page that’s responsive and compatible with modern web design sensibilities. Microsoft has warned us against modifying it, lest we pay the “modification tax,” but our clients keep saying, “Responsive, responsive, responsive.” You’ve got to meet us half-way.

Office Dev PnP Tooling (or something like it) baked in to Visual Studio just as well as the Feature Framework tooling was baked in to VS 2012/2013. And while we’re on the subject, can we please have some less roundabout ways to get things done? As much as I love Vesa Juvonen and the work he and his team have done, this needs to have some real Microsoft institutional oomph behind it.

And while we’re at it, let’s have a better story for client-side, non-App/Add-in-oriented development. SharePoint 2013 is approaching the sunset and 2016 is being born, and I’ve still yet to actually write an app for a client. They don’t want to set up that infrastructure, and if they have no intention of adding untrusted stuff from the internet they shouldn’t have to.

Got it, got it, got it. I’m so psyched for the SharePoint Framework, I can barely contain myself.

Okay, this isn’t SharePoint so much, but what’s the deal with javascript Intellisense in an Angular app in Visual Studio? Eh, it won’t be much of an issue for me in the future, since after recently completing a moderately large javascript project, I now solemnly swear to use Typescript forever and ever, amen.

They explicitly showed people using the SharePoint Framework using VS Code. More modern “cool” tools, less monolithic IDEs. Nice.

Either integrate Yammer like you promised or get rid of the damn thing. I was at the SharePoint Conference in Vegas where they announced the acquisition, and the two products seem no better integrated today than they were then. SharePoint 2013 could have been the launchpad from which real Office Social Networking took off, but instead Microsoft strangled it with a garrote from the back seat of a late 70’s model sedan.

Some kind of way forward for InfoPath! Surely when it comes to something as basic to human business life as forms, there must be some happy medium between “let’s use an end-of-life’d technology that no one at Microsoft will touch with a ten foot pole” and “time to write another fat check to that javascript developer!” Sure I’m usually the javascript developer they write that fat check to, but I do have some sympathy for my clients.

Nope. Yammer and InfoPath are still dead as disco. Sorry, Tessio. It’s just business.

A device that sends an electric shock to any person who attempts to use SharePoint as a relational database back-end for a super-customized, nowhere-near-the-box, not-at-all-like-SharePoint front-end. Yes, this device would probably kill me, but my smoking corpse could serve as a warning to others…

Not only did I not get this, but the SharePoint Framework will probably encourage me to do more of that type of development. It’s probably best for my health anyway.

The Future of SharePoint

Today, at 12:30 PM my local time, Microsoft is doing a big reveal at an event they call, “The Future of SharePoint.” It’s apparently going to be something big, because the SharePoint Social Media Universe has been able to talk of nothing else for weeks now.

I’ll be anxiously watching this event today, but before I do, I thought about the things that I’d like to see in the future of SharePoint.

Crystal Ball on Ice, courtesy of https://www.flickr.com/photos/punktoad/4302556980, (CC BY 2.0)

Crystal Ball on Ice, courtesy of https://www.flickr.com/photos/punktoad/4302556980, (CC BY 2.0)

Now these are not prognostications. I know an MVP or two, but they’ve remained faithful to their NDA’s. This is just what I would like to see happen with SharePoint.

  1. A Master Page that’s responsive and compatible with modern web design sensibilities. Microsoft has warned us against modifying it, lest we pay the “modification tax,” but our clients keep saying, “Responsive, responsive, responsive.” You’ve got to meet us half-way.
  2. Office Dev PnP Tooling (or something like it) baked in to Visual Studio just as well as the Feature Framework tooling was baked in to VS 2012/2013. And while we’re on the subject, can we please have some less roundabout ways to get things done? As much as I love Vesa Juvonen and the work he and his team have done, this needs to have some real Microsoft institutional oomph behind it.
  3. And while we’re at it, let’s have a better story for client-side, non-App/Add-in-oriented development. SharePoint 2013 is approaching the sunset and 2016 is being born, and I’ve still yet to actually write an app for a client. They don’t want to set up that infrastructure, and if they have no intention of adding untrusted stuff from the internet they shouldn’t have to.
  4. Okay, this isn’t SharePoint so much, but what’s the deal with javascript Intellisense in an Angular app in Visual Studio? Eh, it won’t be much of an issue for me in the future, since after recently completing a moderately large javascript project, I now solemnly swear to use Typescript forever and ever, amen.
  5. Either integrate Yammer like you promised or get rid of the damn thing. I was at the SharePoint Conference in Vegas where they announced the acquisition, and the two products seem no better integrated today than they were then. SharePoint 2013 could have been the launchpad from which real Office Social Networking took off, but instead Microsoft strangled it with a garrote from the back seat of a late 70’s model sedan.
  6. Some kind of way forward for InfoPath! Surely when it comes to something as basic to human business life as forms, there must be some happy medium between “let’s use an end-of-life’d technology that no one at Microsoft will touch with a ten foot pole” and “time to write another fat check to that javascript developer!” Sure I’m usually the javascript developer they write that fat check to, but I do have some sympathy for my clients.
  7. A device that sends an electric shock to any person who attempts to use SharePoint as a relational database back-end for a super-customized, nowhere-near-the-box, not-at-all-like-SharePoint front-end. Yes, this device would probably kill me, but my smoking corpse could serve as a warning to others…

SharePoint Saturday, NYC

I had a total blast speaking at SharePoint Saturday this past weekend. I admit I was slightly terrified at the prospect of speaking in front of a crowd of seasoned IT professionals… I was worried I’d get something wrong and provoke the ire of the crowd. But, as it turned out, the crowd was delightful and enthusiastic.

My presentation was entitled, “Love in the Time of Javascript: Useful Patterns for Client-Side Code in SharePoint.” A friend of mine from Google said that comparing javascript to cholera was unfair to cholera…

It went well, but I experienced particular delight in a trick I pulled that worked gloriously. Everyone who’s been to these sessions knows that people kind of drift in and out of them, as they discover that the session they’re attending isn’t exactly what they’re looking for, and that another session going on at the same time might be more fulfilling. Nothing wrong with that. This ain’t the theater, but it’s still slightly distracting for presenters.

So I thought, “How long would it take someone to determine that my presentation was not for them?” I guesstimated that it’d be about twelve minutes. So, before the presentation began, I wrote “9:12” on one of my business cards, and handed it out to a gentleman in the front row.

I began my presentation, and, lo and behold, someone starts making his way out. I glance at the clock on my presenter computer. 9:12 exactly! I say to the man in the front row, “Sir, what time does it say on that card I gave you?”

“9:12.”

“What time is it now?”

“9:12.”

“9:12! First walkout! I called it!”

I swear upon my very life that I didn’t pre-arrange it with the guy who left.

Oh yeah, I spoke a bit about SharePoint and javascript, too. But clearly, pulling off a magic trick was the highlight of my SharePoint Saturday.

For those who are interested, here is the PowerPoint presentation for Love in the Time of Javascript: Useful Patterns for Client-Side Code in SharePoint.

More SharePoint Annoyances: User Field Defined in XML Not Appearing in ListData.svc REST/Odata Output

Here’s another one my improv peeps can ignore.

So here’s the deal: My company has declared that they’re going to be moving our SharePoint installation to Office 365 some time in the not-too-distant future. There go my farm solutions. Add to that the fact that SharePoint 2013 is deprecating the sandbox and the writing on the wall says I’d better learn JavaScript ASAP.

So I work on a sandbox solution (since I’m still on 2010) to deploy some lists, with an included web part that uses JavaScript to query ListData.svc (and do neat stuff with the interface using knockout).

I have a User field in one of the lists called “Owner.” However, when I query ListData.svc, it doesn’t appear. (No, it’s not deferred. It’s just not there. The OwnerId field isn’t there, either.)  I bang my head against the wall a bit.  Then I add another User field to my site columns, content type, and list in Visual Studio.  Still no dice.

Then I think to add a field using the plain-old web interface.  Suddenly it works.  Could I have been defining my User columns incorrectly all this time?

[sourcecode language=”xml”]

[/sourcecode]

(I changed the name of the column, in case “Owner” was a reserved word in OData or something. Don’t judge! I was desperate!)

Apparently, all this time I’d been missing the List=”UserInfo” parameter in my list definitions. And the only… ONLY symptom I’ve ever seen from this is that the field doesn’t appear when queried via the REST interface.

Once again, SharePoint has driven me to distraction (and blog posting).

Exporting XSLTListView Web Parts to Other Webs + In Place Records Management Enabled = Null Reference Exception

Here’s the scenario: In SharePoint, you want to view one or more lists from one web in a site collection in a different web on the same site collection. What do you do? That’s easy: You go to SharePoint Designer, go to the original list view, export the XSLTListView web part that represents that view, load it into your other web and place it in whatever web part page you’d like. Boom. Dashboard.

Unless, of course, you’ve got the In Place Records Management feature enabled. In that case, you’re screwed. Everything will look fine for a while. But eventually, all of the views of your original list will fail. You will see the dreaded:


Server Error in '/' Application.
________________________________________
Object reference not set to an instance of an object.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.NullReferenceException: Object reference not set to an instance of an object.

Source Error:
An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.

Stack Trace:

[NullReferenceException: Object reference not set to an instance of an object.]
Microsoft.Office.RecordsManagement.RecordsRepository.Records.GetCachedAllowManualRecordDeclarationSetting(CachedList list, Hashtable siteProperties) +3
Microsoft.Office.RecordsManagement.Controls.<>c__DisplayClass1.b__0() +164
Microsoft.Office.Server.Utilities.MonitoredScopeWrapper.RunWithMonitoredScope(Action code) +39
Microsoft.Office.RecordsManagement.Controls.DeclareRecordAction.GetDeclareRecordInfo() +158
Microsoft.Office.RecordsManagement.Controls.InPlaceRecordsRibbon.Page_PreRenderComplete(Object sender, EventArgs e) +74
System.EventHandler.Invoke(Object sender, EventArgs e) +0
System.Web.UI.Page.OnPreRenderComplete(EventArgs e) +11058669
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +3671

Why, SharePoint!? WHY!? (Seriously, if I had a nickel for every time I shouted that…)

Well, with the help of our good friend .NET Reflector, let’s take a closer look at that stack trace, shall we?

Microsoft.Office.RecordsManagement lives in Microsoft.Office.Policy.dll. I open it up and take a look at GetCachedAllowManualRecordDeclarationSetting(CachedList list, Hashtable siteProperties). Not much there…

[sourcecode language=”csharp”]
internal static bool GetCachedAllowManualRecordDeclarationSetting(CachedList list, Hashtable siteProperties)
{
if (list.RecordsUseListSetting)
{
return list.RecordsAllowManualDeclareSetting;
}
return GetCachedAllowManualDeclarationSiteSetting(siteProperties);
}
[/sourcecode]

Nothing that’s going to throw a NullReferenceException unless the cached list itself is null. So let’s travel up the stack a bit to Microsoft.Office.RecordsManagement.Controls.<>c__DisplayClass1.b__0().

[sourcecode language=”csharp”]
public void b__0()
{
SPList list = SPContext.Current.List;
if (list != null)
{
CachedArea rootArea = CacheManager.GetManagerForContextSite().ObjectFactory.RootArea;
CachedList cachedList = CommonUtilities.GetCachedList(SPContext.Current.Web, SPContext.Current.ListId);
if (list != null) // <- WTF!? (This comment added by me.) { this.declareRecord.iprList = Records.GetCachedAllowManualRecordDeclarationSetting(cachedList, rootArea.Properties); if (this.declareRecord.iprList) { this.declareRecord.userHasRights = Records.CachedDoesUserHavePermissionsToDeclare(list, rootArea.Properties); } } } } [/sourcecode] Ah HA! The cached list is null! The inner null check is clearly meant to check the null-ness of cachedList and not list! So, thanks to a clear, obvious bug in SharePoint, you can’t use XSLTListView Web Parts on other webs in your site collection if In Place Records Management is turned on. Unfortunately, the only solution is to turn it off.

Note: I upgraded my development SharePoint instance to the February 2012 CU. This bug still exists in assembly file version 14.0.6116.5000.

Hey, SharePoint: Why Do You Screw Up My Content Type When I Deploy It Through Visual Studio?

So, we all love the way Visual Studio 2010 allows us to debug our SharePoint code with a single bounce on the F5 button, right? Isn’t it nice the way we can deploy with confidence, knowing that we debugged our code in the dev environment? Surely, our code and configurations will act exactly the same way when we deploy them with Add-SPSolution as they do when we deploy them with F5. Right?

Well then what the hell is up with this:

I’m doing something that I think is pretty typical. I’ve created a content type, descended from Document, to go into a document library, like so:

[sourcecode language=”xml”]












[/sourcecode]

And I’ve created a document library to hold documents of this content type, like so:

[sourcecode language=”xml”]







(blah blah blah)

(blah blah blah blah blah)


[/sourcecode]

So can you tell me why I see the following when I hit my F5 key?

A SharePoint List Configuration Screen

Hm, that’s odd. I called my content type “Project Document” not “Project Documents.” Project Documents is the name of the document library itself. Let’s take a closer look at that content type, shall we?

A SharePoint Content Type Configuration Screen

What the WHAT? That’s no content type, that’s a list instance! I wondered what I’d done wrong. It’s certainly not out of the question for me to screw up a SharePoint XML configuration somewhere. Hell, screwing that up is most of what I do all day. So I went to my test server, where I’d deployed a slightly different earlier version. The document library and content type appeared normal. Could there possibly be some difference in the way I deployed the project? I deployed the .wsp manually on the dev box… the very same .wsp I’d just debugged with F5.

A SharePoint List Configuration Screen, from a manually deployed project.

But that looks perfectly normal. What about the content type itself?

A SharePoint Content Type configuration Screen.

So… I guess this means I can’t trust content deployed through Visual Studio anymore. Hey, it’s not like I needed a streamlined workflow or anything.

My Upgrade Actions Can’t Have a Comment? Really, SharePoint?

So I’m doing new work on a SharePoint feature that’s already deployed, so naturally, I have to do some upgrade actions to deploy some new fields to a content type. There are a few fields to add, and since the AddContentType field doesn’t have any naming elements, I decide to throw in some comments before each entry, so I know which field is which and I make sure I haven’t forgotten any. Everything compiles fine and Update-SPSolution works fine. Then, I try to run my upgrade and I get the following error:

Really, SharePoint? You can clearly see that it’s a comment, and yet you still just barf on it rather than just ignoring it. WHY!?

Adventures in Uninformative SharePoint Messages, or The Sandbox is Too Damn Busy for Your List Receiver

Still here? Great. So, here’s the situation. Tell me if it seems crazy. There are things that, to me as a programmer, don’t seem crazy at all, while more seasoned SharePoint developers would look at what I was doing and scream, “Are you mad?” Like iterating through SPList.Items() in a foreach loop without first putting them into an SPListItemCollection, for example.

Anyway, I have the following situation: A project tracking list, which has a “Primary Technical Lead” field and a “Secondary Technical Lead” field, both of which are single User-type. I need to create a “Team Members” field, which is a multi-User type. Upon creation of that field, I need to populate it with both the value from the Primary and Secondary tech lead fields. Naturally, I chose to implement this one-time setup in the FeatureActivated event receiver.

Additionally, I want to make sure that whenever a tech lead is changed, that that change is reflected in the Team Members field. I also want to make sure that you can’t delete someone from Team Members if they’re still a tech lead. Naturally, I chose to implement this as an ItemUpdating event receiver.

Every time I tried to activate the solution, however, I always got the following error:

Unhandled exception was thrown by the sandboxed code wrapper’s Execute method in the partial trust app domain: The sandboxed code execution request was refused because the Sandboxed Code Host Service was too busy to handle the request.

Well, excuuuuuuuuse me!

Now, I wasn’t entirely un-clever about this. Of course my ItemUpdating event was firing when I was trying to populate the TeamMembers field. (Okay, I’m kind of lying. There was a lot of blank “WTF?” going on in my head before I realized that the ItemUpdating event was firing. Then I went through the feature activation in the debugger, and noticed that the exception was thrown when I called SPListItem.Update() or SPListItem.SystemUpdate(), which I tried in desperation.) But my ItemUpdating method should have just quickly exited upon not seeing the fields that it was worried about in the AfterProperties. Still, worried about my logic, I commented out my routine line by line. Until finally, my entire ItemUpdating receiver looked like:

[sourcecode language=’c#’]
public override void ItemUpdating(SPItemEventProperties properties) {
// Lots of commented-out lines
base.ItemUpdating(properties);
}
[/sourcecode]

And still, Sandbox is Too Damn Busy.

Then I went to the List Receiver’s Elements.xml file, and commented out the <Receiver…><Type>ItemUpdating</Type>…</Receiver> part. And lo and behold, the Sandbox would suddenly take my calls again.

I then created the simplest test case. One list. One ItemUpdating event receiver which does nothing. One FeatureActivated event receiver that updates a list item. Activation == game over.

Now I understand why updating a ListItem that has an ItemUpdating receiver from a FeatureActivated receiver might be a problem. But, once again, SharePoint has vomited forth one of the least useful error messages possible.