Solved: Issue with SharePoint Rest API Document Upload – Solving the case of the single apostrophe/quote in the URL POST

So I ran across an interesting mystery a while back that I thought I would share the fix for once I had time to document it. I have a client that uses an embeddable SharePoint page within CRM to allow document uploads right from the front entity screens without having to deviate to another screen and for the most part things have been going well. Until…the mystery began.

The problem: In some sporadic cases when uploading documents via POST to the REST API users would encounter an issue with the dynamically generated URLs from SharePoint that contain single apostrophes or quotes in the library name that would be used in the POST URL.

Errors may look like:

{"error":{code":"-1,Microsoft.SharePoint.Client.InvalidClientQueryException","message":{"lang":en-US","value":"The expression\"web/getfolderbyserverrelativeurl('yourfolder/O'Lastname, Firstname - 23424ID')/files/add(overwrite=true,url='filename.pdf')\" is not valid."}}}

The odd part about that? If you browse the library on its own, it’s fine! However, trying to post to the REST API with an improperly escape quote is not. So let’s fix that.

The solution: It’s all in how you build the URL with properly escaped characters.

Snippet in question:

    // Add the file to the file collection in the Shared Documents folder.
    function addFileToFolder(arrayBuffer) {

        // Get the file name from the file input control on the page.
        var parts = fileInput[0].value.split('\\');
        var fileName = parts[parts.length - 1];

        // Construct the endpoint.
        var fileCollectionEndpoint = String.format(
                "{0}/_api/web/getfolderbyserverrelativeurl('{1}')/files" +
                "/add(overwrite=true, url='{2}')",
                serverUrl, serverRelativeUrlToFolder, fileName);

        // Send the request and return the response.
        // This call returns the SharePoint file.
        return jQuery.ajax({
            url: fileCollectionEndpoint,
            type: "POST",
            data: arrayBuffer,
            processData: false,
            headers: {
                "accept": "application/json;odata=verbose",
                "X-RequestDigest": jQuery("#__REQUESTDIGEST").val(),
                "content-length": arrayBuffer.byteLength
            }
        });

Fixed snippet:

    // Add the file to the file collection in the Shared Documents folder.
    function addFileToFolder(arrayBuffer) {

        // Get the file name from the file input control on the page.
        var parts = fileInput[0].value.split('\\');
        var fileName = parts[parts.length - 1];

        // Construct the endpoint.
        var fileCollectionEndpoint = String.format(
                "{0}/_api/web/getfolderbyserverrelativeurl('{1}')/files" +
                "/add(overwrite=true, url='{2}')",
                serverUrl, serverRelativeUrlToFolder.replace(/\%27/g,"''"), fileName);

        // Send the request and return the response.
        // This call returns the SharePoint file.
        return jQuery.ajax({
            url: fileCollectionEndpoint,
            type: "POST",
            data: arrayBuffer,
            processData: false,
            headers: {
                "accept": "application/json;odata=verbose",
                "X-RequestDigest": jQuery("#__REQUESTDIGEST").val(),
                "content-length": arrayBuffer.byteLength
            }
        });

Conclusion? With the replace regex fix in place it will now take every occurance (and not just the first, thanks regex) of a single quote that come as a part of the folder directory and properly escape them when I want to post a file back with the API.

Key change:

serverRelativeUrlToFolder.replace(/\%27/g,"''")

Everybody wins now, espcially the people out there with apostrophes in there names and folder names with titles that still need the quotes in them! Hope this helps.

References:

Solved: The length of the URL for this request exceeds the configured maxUrlLength value.

Anyone ever run into the following before? I ran into this regarding a request into the SharePoint Rest API.

The length of the URL for this request exceeds the configured maxUrlLength value.

This because the IIS default maximum length for an URL is 260 characters. If a URL request is longer, the above error will occur.

To fix this you can increase the maxURLlength value, add it to your web.config file in the IIS virtual Directory.

<configuration>

  <system.web>

    <httpRuntime maxUrlLength="5000" />

  </system.web>

</configuration>

It will be likely you will already have most of this snippet in place so don’t break your config; just add the maxUrlLength property into your existing httpRuntime section and you should be good to go. Do know any web.config changes may cause a service interruption so test in dev, beta, QA and pre-prod before ever changing in prod! Hope this helps, questions are welcome!

SharePoint/PowerShell – Get the AD groups associated with a site collection and output to CSV file

Need to deliver or better understand the AD groups associated with your SharePoint site collection? Try this:

$SPWebApp = Get-SPWebApplication http://sitecollectionURLhere/

foreach ($SPSite in $SPWebApp.Sites)
{
    write-host -foregroundcolor green "Working on Site Collection: " + $SPsite.RootWeb.Title 
    $SiteURL = $SPsite.RootWeb.URL
    $ADgroup=Get-SPUser -Web $SiteURL -Limit ALL | Where { $_.IsDomainGroup }
}
echo $ADgroup | Export-Csv "C:\Temp\FileNameGoesHere.csv"

PS1 download is here: https://1drv.ms/u/s!Ag4C3w6EUQIggowvfXrE0Z3tfWKJeA

Help! Need Help Diagnosing A 500 Errors In SharePoint? Try This…

Imagine the nightmare…you decided to sneak in a web part deployment in right before the start of the business day. Right after your deployment you see that the site is about to come back up…and…then nothing. A blank screen. In desperation you open Internet Explorer to try and see if it loads there as well..nothing but a 500 error. Then, the feeling rushes over you that this was a very bad decision. While we should address why you were doing an early morning deployment we shall spare you. 🙂 So what do you do now?

One of the best ways to see what is going on with a 500 error is to enabled Failed Request Tracing in IIS for the web site in question. Once enabled you can replicate the issue by refreshing the browser a few times; this should be more than enough to capture a few. Once captured then you will usually see where the issue is identified (especially with web.config changes that happen).

To do this:

1) Open IIS

2) Select the web site in question and open the Features View

3) Under the IIS section select “Failed Request Tracing” by double-clicking it

FRT1

4) In the top right hand corner click the message in the Alerts section

FRT2

5) When the pop-up comes up then select to enable and take the default directory (unless you need it elsewhere, then specify another location) and hit OK

FR3

6) Next, under actions select “Add…” and select “All content (*)” and click Next

FRT4

7) Indicate the status code of 500 (and others where applicable) and click next again

Frt5

8) Indicate your trace providers and click Finish

FRT6

You should now see your created Failed Request Tracing Rules.

FRT7

Now go and refresh the browser a couple times to see your error again. Once that is logged then go to the trace logs. To find that location go back to the site in features view, select Failed Request Tracing and select “View Trace Logs…”

FR8

Double click to view the recorded log (you can use IE):

FRT9

Viewing these should at least help to identify the obvious when it is a line in the web.config or when there has been a setting changed as a result of saving a configuration option in SharePoint (or 3rd party products or web parts in SharePoint). Hope this helps, happy troubleshooting. Questions are always welcome.

 

How To Make A SharePoint List System.String Column (Built From An BCS External Content Type List) Into A Clickable Hyperlink

So for this example I have a SQL database that I am pulling into an external content type called OfficeLocations. From this external content type I have created a SharePoint list that is referencing it. The issue I ran into is that the GoogleMapLink text coming from SQL was in a NVARCHAR format (which was System.String on the external content type and Single line of text for the column) and you cannot modify those columns.

officelocationslistsetting

This left me with a list that had a link but it was not clickable:

officelocationslistsetting1

Annoying right? So what do we do? Let’s mess with the XSL template of the item and see what happens…so I popped into SharePoint designer and created a view off of the SharePoint list and modified the XSL template of the GoogleMapLink column to use the string field as the href of the <a> tag and supplied my own text to give the link a more user friendly readable URL.

To the code (the bolded elements are the only additions I made):

<xsl:template name="FieldRef_Text_body.GoogleMapLink" ddwrt:dvt_mode="body" match ="FieldRef[@Name='GoogleMapLink']" mode="Text_body" ddwrt:ghost="hide">
 <xsl:param name="thisNode" select="."/>
 <xsl:variable name="currentValue" select="$thisNode/@*[name()=current()/@Name]" />
 <xsl:choose>
 <xsl:when test="@AutoHyperLink='TRUE'">
 <xsl:value-of select="$thisNode/@*[name()=current()/@Name]" disable-output-escaping ="yes"/>
 </xsl:when>
 <xsl:otherwise>
<strong><xsl:element name="a"></strong>
<strong> <xsl:attribute name="href"></strong>
 <xsl:value-of select="$thisNode/@*[name()=current()/@Name]"/>
<strong> </xsl:attribute></strong>
<strong> <xsl:text>Link</xsl:text></strong>
<strong> </xsl:element></strong>
 </xsl:otherwise>
 </xsl:choose>
 </xsl:template>

This created clickable links titled “Link” on the list itself. You can see the results below:

officelocationslistsetting2

Much cleaner, right? If you wanted the full link you could do that too. Hope that helps.