How do I - Convert a SharePoint List Private View to a Public View?

Have you ever started creating a list view in SharePoint and because you're experimenting, you chose to make it a "Private" view?  Then before long the view evolves to be extremely useful in your work, but you cannot make it public for others to see and use?
Well fear no more.  This guide will walk you through Step-by-Step on how to convert your existing private list views into new public views that everyone can use.

1.  Begin by navigating to the target list.  In my example, I have a list called "Demo Convert Views" in which I created a personal view called "Cs Private View" which has several customizations for demo purposes.

2.  Now double click the ellipses (...) and from the dropdown menu, click the "Create View" option.

3.  The View Type page will allow you to define your view in different formats, but we're more interested in the "Start from an existing view" option at the bottom.  Here all current views accessible to you, INCLUDING your Personal Views, are listed.  You can thus clone a view from any of those.  In our case, we're going to click on the "Cs Private View" to use it as the foundation for the new view.

4.  The problem quickly becomes apparent when we see that our "View Audience" selection is locked into "Create a Personal View" because the view we used as a base was a personal view.  Herein lies the problem.  Time to put on your white hat and get hacking.

5.  We begin by activating the Developer Mode (in IE) or the Element Inspector (in Chrome).
6.  To activate IE Developer Mode, press the F12 key.  You should now have a panel open up below displaying the underlying HTML for the page.  Ensure that you're on the "DOM Explorer" tab.

7.  Now it is time to expand the DOM in search of that "Create a Public View" radio button.
8.  Expand the "<form" section.
9.  Scroll to the bottom of the "<form>" tag and locate the "<div class="ms-core-overlay"" tag and expand it.

10.  Inside that tag, locate the "<div id="contentRow">" tag and expand it.
11.  Inside that tag, locate the "<div id="contentBox"" tag and expand it.
12.  Inside that tag, locate the "<div id="DeltaPlaceHolderMain">" tag and expand it.
13.  Inside that tag, locate the "<table width="100%" class="ms-v4propertysheetspacing"" tag and expand it.
14.  Inside that tag, locate the "<tbody>" tag and expand it.
15.  Inside that tag, locate the "<tr>" tag and expand it.
16.  Inside that tag, locate the "<td>" tag and expand it.

17.  Scroll down past the series of "<input>" tags to the "<table" tag below them and expand that.
18.  Inside that tag, locate the "<tbody>" tag and expand it.
19.  There will be several "<tr>" tags.  Scroll down and locate the "<!--Audience-->" marker and expand the 4th "<tr>" tag below it.
20.  Inside that tag, locate the "<td class="ms-authoringcontrols" id="onetidViewAudience">" tag and expand it.
21.  Inside that tag, locate the "<table>" tag and expand it.
22.  Inside that tag, locate the "<tbody>" tag and expand it.

23.  Inside that tag, locate the 3rd "<tr>" tag and expand it.
24.  Inside that tag, locate the 2nd "<td>" tag and expand it.
25.  You should now see an "<input>" tag.

26.  You will notice the tag has a property called "disabled=""".  We want to delete this property, but that's not as straight forward as it sounds.
27.  Double click on the word "disabled".
28.  The browser would now give you the ability to change the name of the tag.

29.  Delete the tag by pressing the "Delete" key on your keyboard while it's selected.
30.  Now press "Enter".
31.  You will notice the "<input>" tag now looks a little weird, but that's OK.

32.  Next you want to right click on the "<input>" tag line.
33.  From the dropdown, click "Delete element".
34.  The entire line should now disappear.

35.  Now press "Ctrl+Z" on your keyboard to bring the element line back.
36.  You will notice that the weird ="" text is no longer there.

37.  You can now close the developer panel.
38.  You will notice that you can now change the radio button for the "View Audience" from "Create a Personal View" to "Create a Public View".
39.  Name your view and click the "OK" button to save the new view.

40.  Your Personal view has now been cloned into an exact replica Public view!  😎

Happy coding.

How do I - Retrieve the LoaderExceptions property?

If you've spent any time in the SharePoint world lately, you've undoubtedly been exposed to the PnP project and it's super powerful extensions for SharePoint.  While PnP is not officially supported by Microsoft, it is Community Supported by the SharePoint Product Team.  PnP can be very fussy at times with strict dependencies on very specific DLL versions.  The most frustrating thing is when you are presented with this error:

Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information.

I never understood why the exception code that is throwing the error doesn't just provide the LoaderExceptions info in the error message, but such is life.  When we get this error, we can deal with it in the following manner:

Happy coding

How do I - Format a numerical value in a calculated SharePoint field?

If we remember our SharePoint Power Tip on calculated fields, then we'd know we can use Excel formulas to make this work the way we want.  In my case, I was trying to display the age of a ticket in days, on it's InfoPath customized form.  Sounds easy enough right?

NOW() - Created

That should do it, right?
Unfortunately, that displayed a value with fractions.  Not quite what we want.  OK, so let's just round the thing then, and while we're at it, round it to 0 decimals thus:

ROUND(NOW() - Created, 0)

Alas, that did not do it either.  Hopping into Excel, I used text formatting to achieve the goal.  The final calculation was:

=TEXT(ROUND(NOW() - Created, 0), "0")

Happy coding.

SharePoint Power Tip - Calculated field formulas

When we are dealing with Calculated fields in SharePoint lists, it's good to remember that lists are basically Excel sheets.  To whit, we can use almost all the same formulas in a calculated field as we do in Excel.  I often go into Excel to work out my formula (since the interactive error messages are better) and then just copy the formula from Excel to my field definition in SharePoint.
If it works in Excel, it probably works in SharePoint! 😉

Happy coding.

Which NuGet package contains System.Web.Http?

NuGet is a wonderful thing, but when the package name does NOT reflect the DLL name you're looking for, it can become quite a harrowing experience!  Such has been the case with the System.Web.Http.  Note that I said System.Web.Http and NOT System.Net.Http! 😉
This little gem finds itself embedded deep inside the Microsoft.AspNet.WebApi.Core package.  I can't believe we weren't able to infer the package name from the DLL.  😇

Happy coding.

How do I - Fix the "You must add a reference to assembly netstandard" error?

When using NuGet, we can easily run into assembly reference issues.  A notorious error message is:

CS0012: The type ‘System.Object’ is defined in an assembly that is not referenced. You must add a reference to assembly ‘netstandard, Version=, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51’.

This can be very confusing especially if your app is NOT using the .NET Standard library at all.  Luckily the fix is easy enough.  Simply crack open your app.config or web.config file and added the following:

Happy coding.

How do I - Calculate time difference between two date objects in C#?

The time difference between two date objects is easily calculated using the TimeSpan class thus:

Happy coding


OK, so yesterday I posted an article about how standards should be followed and the dire consequences for everyone if they aren't.  OK, OK, it wasn't really that dark, but the point just being that I got on my little soap box yesterday and went off on a little rant after solving a problem that had me stymied for two and a half days with no help from the internet, StackExchange or my MVP cadre.  I was frustrated.  Of course, after posting the article, I get texts from my friends and colleagues saying "Hey C, nice rant, but you didn't really provide a clear answer to the problem in your post."
After re-reading my post, I have to agree.  So I whipped the code from my Quix toolbox into a quick Gist that will hopefully save someone else the frustration in the future. 😎
The code is pretty self explanatory.

All you have to do to incorporate this into your own C# program is to include it in your project and then call the getInfoPathAttachments() method while passing it two arguments.
The first is the XML document constituting the InfoPath form's XML which is easily loaded to the standard System.Xml.XmlDocument object.
The second is the node path where the attachments are located in your form.  In my case, the control was called "Attachment" and was literally hanging straight off the root of the document so my node path was "/my:myFields/my:Attachment".
The method will return a list of MemoryStream objects which you can then process any way you like such as saving to disk or processing further etc.

Happy coding.

When standards aren't... aka how do I deal with multiple file attachments in InfoPath

As we all know, Microsoft has been proclaiming InfoPath to be "dead" for many years now, but it's not until recently with PowerApps that we've seen any glimmer of hope for a replacement.  As such, InfoPath lives on and gets migrated from one version of SharePoint to the next version after version after version...

One of the things that made InfoPath special was the ability for users and designers to tinker with the template and move stuff around, add and remove fields etc. and it would maintain all historic schemas in SharePoint so that any older content that was created with said schema, could be opened with the appropriate schema when needed.
Enter migration time.  Queue the dramatic music please.

All migration tools, that's right, every single last one of them, when migrating InfoPath libraries, will only migrate the latest .xsn schema which of course means that ALL forms created with older schemas is now broken!  This stems from the fact that migration tools use the API's provided by Microsoft and the fact that the APIs do not provide access to older schemas.
Being the industrious little problem solver that I am, I wrote my own tool to work around this problem.  The tool simply downloads the latest .xsn from the target library, extracts the template.xml and manifest.xsf for parsing and then iterates the schema node by node while seeking matching nodes in the original source XML data and reconstructing the new target XML on the fly.  Upon completion the new XML document is upload to the target and it fully usable as is.  This works GREAT!

Then we encountered multiple file attachments.
Now I don't know if you've even ventured down the rabbit hole that is InfoPath File Attachments, but let me tell you... it's a mess!  What little information is available on the web is old, outdated and hardly applicable.  Oh and did I mentioned nobody and I mean NOBODY talks about dealing with MULTIPLE FILE ATTACHMENTS!!!

The first glimpses of hope I could gleam from scouring the internet was this Microsoft support article titled "How to encode and decode a file attachment programmatically  by using Visual C# in InfoPath 2003".
Right in the introduction, the article had a reference pointing to an updated version titled "How to encode and decode a file attachment programmatically  by using Visual C# in InfoPath 2010 or in InfoPath 2007".
I read both to be sure.  There's very little difference from a code perspective between the two, but I'll reference code from the 2010 example here.

The article first walks you through the InfoPathAttachmentEncoder() class which is pretty straight forward, but it is important to note that in line 45 they are reading the file to be attached as Unicode.  In line 78 the ToBase64Transform is used to convert the unicode binary of the file on disk to text in Base64 format, that can fit in XML.  Finally in line 93, the memory stream is grabbed as ASCII text and returned to the caller to be inserted to the InfoPath form as an attachment.

The decoder class that follows is the same except in reverse, taking in the base64, ASCII data and then converting it into a byte array in a memory stream in lines 25/26.  A BinaryReader() then reads the memory stream to decode the attachment.

They never delve into dealing with multiple attachments at any point.  In fact the reference to the attachments in XML is very small and always worked from a view of single file attachments as can be seen in the code to save the attachment thus:

As can be seen from line 8, the use of the SelectSingleNode() method assumes only one file attachment.  So this helped me understand the magic behind how the documents are encoded and stored in the XML of the InfoPath document, but it still wasn't giving me any glimpses into dealing with multiple attachments.  Further searching brought me to the site and in particular their "Top 10 questions about InfoPath attachments" article.  Eureka!  I thought.  This has to be it.  They had multiple questions with answers and links to videos that would hold the key information I sought... except... their video links were all dead. 😡
My heart sank to new lows as my struggle entered day two.  I stumbled upon this article from Kunaal Kapoor titled "Getting InfoPath attachments from a submitted form" wherein he explains how it could be done using the XSD Visual Studio tool to build classes off the InfoPath template.  This seemed like a major departure from my current implementation, but desperate times you know...
So I tried it and as I suspected, it didn't work.  OK, back to my former path.  I know it's in there in the XML, I just have to find it.

OK, back to basics.  Rule #1 of debugging.  NEVER ASSUME ANYTHING!
So let's check, double check and triple check all our bases again.
Let's look at the attachment definition in the form.

OK, it's a simple field control, of type Picture or File Attachment (base64) with the Repeating option checked.  Nothing out of the ordinary here.
Next I decided to compare the character by character, line by line results of the files.  Time for my beloved Beyond Compare!  If you don't have this tool in your toolbox, you're seriously missing out on productivity.  The folks at Scooter Software does an awesome job with this gem of a tool.  A definite must have for every geek.
As I did my comparison and got to the end of the first attachment, this is what I noticed:

On the left is the original source file that had 3 attachments.  On the right is the processed result with just one.  Obvious right?  So then the question is... why do we only see one Attachment node in the code during processing.  The answer is based on the presupposition that repeating data represented in standard XML is represented in a collection node thus:

    <File Name="abc.doc"/>
    <File Name="xyz.doc"/>
    <File Name="ugh.doc"/>

Instead, the way InfoPath chose to represent multiple attachments in this case was as follows:

  <Attachment Name="abc.doc"/>
  <Attachment Name="xyz.doc"/>
  <Attachment Name="ugh.doc"/>

As a result, when my code was processing the childnodes of the XML document, looking for a match against the schema in order to rebuild the new target document, it found the first Attachment node and was satisfied and then moved on.  If the attachment was represented in a standards based collective node, all the files would have been caught.

It just goes to show you.  Rule #1 is so true.  Never assume anything.  Not even when the source is a large, reputable, multi-billion dollar company. 😎

If you'd like to leverage the code I wrote to solve this, I posted a follow on article the following day that can be found here:

Happy coding

How do I - Fix The Standard View of your list is being displayed because your browser does not support running ActiveX controls

After migrating a site from SharePoint 2010 you find that it doesn't display the same way in your new environment. Sure, newer versions of SharePoint is sure to display content slightly differently, but this one's different. Instead of your items scrolling nicely on page in a scrollable box, the entire page now becomes a scrollable grid.


Notice the Access Web Datasheet grid displaying the content on the page.
Now take a look at the migrated content.


Notice the page scroll bar to the right.  The entire page is now scrolling.  In addition, the error message at the very bottom of the page notes:

"The Standard View of your list is being displayed because your browser does not support running ActiveX controls."

The fix is actually pretty straight forward.
Odds are you're using Internet Explorer 11 or later and like most SharePoint sites, you'll need to tell newer versions of IE to interpret the site in Compatibility Mode.  To achieve this simply:

   1.  Click the settings gear in the top right of IE, just below the closing X.

   2.  Click the "Compatibility View settings" option on the dropdown menu.

   3.  The Compatibility View Settings modal window will be displayed.
   4.  By default your site's root domain will be displayed in the "Add this website:" field as in #1 above.
   5.  Click the "Add" button (#2) in order to add the domain to the list (#3) below.
   6.  Click "Close".
   7.  The site should automatically refresh and the content should load the same way as you're used to.