SharePoint Experts, Information Architects, Expert Witness

We provide consulting in a broad array of business and technology from architecture to design to deployment of global systems with a focus on surfacing data in the enterprise. Specialists in Microsoft, we are a premier provider of SharePoint Expertise (including 2016 and Office 365). We also provide Expert Witness/Legal Expert in eDiscovery, source discovery, patent infringement, piracy and more! We also have established SICG DLDS s.a. - our counterpart in Costa Rica that specializes in water systems (http://www.crwatersolutions.com) - Contact me direct: david_sterling@sterling-consulting.com or call 704-873-8846 x704.

Search This Blog

Tuesday, March 22, 2016

SharePoint, BlobCache and HTTP 304's (2013/2016)

As we all know, the "BlobCache" for SharePoint is disabled by default. There are three specific lines that define this in the web.config of the site. The first is the blob cache (and location):

<BlobCache location="C:\BlobCache\" path="\.(gif|jpg|jpeg|jpe|jfif|bmp|dib|tif|tiff|themedbmp|themedcss|themedgif|themedjpg|themedpng|ico|png|wdp|hdp|css|js|asf|avi|flv|m4v|mov|mp3|mp4|mpeg|mpg|rm|rmvb|wma|wmv|ogg|ogv|oga|webm|xap)$" maxSize="10" enabled="false" />

The output cache profiles:

<OutputCacheProfiles useCacheProfileOverrides="false" varyByHeader="" varyByParam="*" varyByCustom="" varyByRights="true" cacheForEditRights="false" />

And the output cache size in MB:


<ObjectCache maxSize="100" />

All of these must be updated for a production site. First off, the Blob Cache - it must be on a drive OTHER than C: and must be enabled. In addition, it is necessary to add the 'max-age" for the blob's otherwise requests to the site will generate lots of HTTP 304's (304 is a successful pull from cache but without the max-age set to a day, it will require two hits and is a drag on performace). 

As we SHOULD all know, you never make hand changes to the web.config in SharePoint. SharePoint stores the web.config in the database and will periodically overwrite the web.config file on disk (particularly true in a multi-server environment). Changes must ALWAYS use the SPWebConfigModification object either using the Object Model or using PowerShell. You would be surprised at the supposed 'experts' that don't know this.

The following PowerShell scripts will update all three of the lines above using SPWebConfigModification. Each of these changes can be identified by the "owner" specified in the script (example: BlobCacheChg) - this allows them to be removed if necessary.

First to change the Blob Cache settings (note the settings in blue):

# SCRIPT FOR UPDATING THE BLOB CACHE:
#
# Get a reference to the object:
$configModEnable = New-Object Microsoft.SharePoint.Administration.SPWebConfigModification
# First enable the cache - set the path of the entry to change
$configModEnable.Path = "configuration/SharePoint/BlobCache"
# Get the enabled attribute:
$configModEnable.Name = "enabled"
# Set the value to true:
$configModEnable.Value = "true"
# Set the sequence (a single modification so 0):
$configModEnable.Sequence = 0
# Set the owner value:
$configModEnable.Owner = "BlobCacheChg"
# Now set the modification type (EnsureAttribute):
$configModEnable.Type = 1
#
# Get a reference to the object:
$configModSetLocation = New-Object Microsoft.SharePoint.Administration.SPWebConfigModification
# First enable the cache - set the path of the entry to change
$configModSetLocation.Path = "configuration/SharePoint/BlobCache"
# Get the location attribute:
$configModSetLocation.Name = "location"
# Set the value to true:
$configModSetLocation.Value = "e:\BlobCache\"
# Set the sequence (a single modification so 0):
$configModSetLocation.Sequence = 0
# Set the owner value:
$configModSetLocation.Owner = "BlobCacheChg"
# Now set the modification type (EnsureAttribute):
$configModSetLocation.Type = 1
#
# Get a reference to the object:
$configModSetMaxAge = New-Object Microsoft.SharePoint.Administration.SPWebConfigModification
# First enable the cache - set the path of the entry to change
$configModSetMaxAge.Path = "configuration/SharePoint/BlobCache"
# Get the max-age attribute:
$configModSetMaxAge.Name = "max-age"
# Set the value to 86400 (seconds = 24 hours):
$configModSetMaxAge.Value = "86400"
# Set the sequence (a single modification so 0):
$configModSetMaxAge.Sequence = 0
# Set the owner value:
$configModSetMaxAge.Owner = "BlobCacheChg"
# Now set the modification type (EnsureAttribute):
$configModSetMaxAge.Type = 1
#
# Apply the changes to the web application:
#
$webApp = Get-SPWebApplication –Identity http://somesite
#
$webApp.WebConfigModifications.Add($configModEnable)
#
$webApp.WebConfigModifications.Add($configModSetLocation)
#
$webApp.WebConfigModifications.Add($configModSetMaxAge)
#
# Apply the changes:
#
$webApp.Update()
#
# Update the farm:
#
$webApp.Parent.ApplyWebConfigModifications()

Updating the Output Cache setting:

# SCRIPT FOR UPDATING THE OBJECT CACHE PROFILES:
# Get a reference to the object:
$configModOCProf = New-Object Microsoft.SharePoint.Administration.SPWebConfigModification
# First enable the cache - set the path of the entry to change
$configModOCProf.Path = "configuration/SharePoint/OutputCacheProfiles"
# Get the useCacheProfileOverrides attribute:
$configModOCProf.Name = "useCacheProfileOverrides"
# Set the value to true:
$configModOCProf.Value = "true"
# Set the sequence (a single modification so 0):
$configModOCProf.Sequence = 0
# Set the owner value:
$configModOCProf.Owner = "ObjCProfileChg"
# Now set the modification type (EnsureAttribute):
$configModOCProf.Type = 1
#
# Apply the changes to the web application:
#
$webApp = Get-SPWebApplication -Identity http://somesite
#
$webApp.WebConfigModifications.Add($configModOCProf)
#
# Apply the changes:
#
$webApp.Update()
#
# Update the farm:
#
$webApp.Parent.ApplyWebConfigModifications()


Updating the Output Cache size:

# SCRIPT FOR UPDATING THE OBJECT CACHE VALUE:
# Get a reference to the object:
$configModObjCache = New-Object Microsoft.SharePoint.Administration.SPWebConfigModification
# First enable the cache - set the path of the entry to change
$configModObjCache.Path = "configuration/SharePoint/ObjectCache"
# Get the maxSize attribute:
$configModObjCache.Name = "maxSize"
# Set the value to true:
$configModObjCache.Value = "256"
# Set the sequence (a single modification so 0):
$configModObjCache.Sequence = 0
# Set the owner value:
$configModObjCache.Owner = "ObjCacheChg"
# Now set the modification type (EnsureAttribute):
$configModObjCache.Type = 1
#
#
# Apply the changes to the web application:
#
$webApp = Get-SPWebApplication -Identity http://somesite
#
$webApp.WebConfigModifications.Add($configModObjCache)
#
# Apply the changes:
#
$webApp.Update()
#
# Update the farm:
#
$webApp.Parent.ApplyWebConfigModifications()

Once these changes are made, the web.config should reflect the updates:

<BlobCache location="e:\BlobCache\" path="\.(gif|jpg|jpeg|jpe|jfif|bmp|dib|tif|tiff|themedbmp|themedcss|themedgif|themedjpg|themedpng|ico|png|wdp|hdp|css|js|asf|avi|flv|m4v|mov|mp3|mp4|mpeg|mpg|rm|rmvb|wma|wmv|ogg|ogv|oga|webm|xap)$" maxSize="10" enabled="true" max-age=86400/>

<OutputCacheProfiles useCacheProfileOverrides="true" varyByHeader="" varyByParam="*" varyByCustom="" varyByRights="true" cacheForEditRights="false" />

<ObjectCache maxSize="256" />

Now of course, you may want to remove these changes at some point - for this, you use the "Owner" specified in the scripts above.

Removing the Blob Cache changes:

# SCRIPT FOR REMOVING BLOB CACHE CHANGES:
# Get the web application:
#
$webApp = Get-SPWebApplication http://somesite
# Mod storage:
$mods = @()
# Get all modifications based on the author:
foreach ( $mod in $WebApp.WebConfigModifications ) {
       if ( $mod.Owner -eq "BlobCacheChg" ) {
              $mods += $mod
       }
}
foreach ( $mod in $mods ) {
       [void] $WebApp.WebConfigModifications.Remove($mod)
}
$webApp.Update()
$webApp.Parent.ApplyWebConfigModifications()


Removing the Output Cache changes:

# SCRIPT FOR REMOVING OBJECT CACHE PROFILE CHANGES:
# Get the web application:
#
$webApp = Get-SPWebApplication -Identity http://somesite
# Mod storage:
$mods = @()
# Get all modifications based on the owner:
foreach ( $mod in $WebApp.WebConfigModifications ) {
       if ( $mod.Owner -eq "ObjCProfileChg" ) {
              $mods += $mod
       }
}
foreach ( $mod in $mods ) {
       [void] $WebApp.WebConfigModifications.Remove($mod)
}
$webApp.Update()
$webApp.Parent.ApplyWebConfigModifications()

Removing the Output Cache size changes:

# SCRIPT FOR REMOVING OBJECT CACHE VALUE CHANGES:
# Get the web application:
#
$webApp = Get-SPWebApplication -Identity http://somesite
# Mod storage:
$mods = @()
# Get all modifications based on the owner:
foreach ( $mod in $WebApp.WebConfigModifications ) {
       if ( $mod.Owner -eq "ObjCacheChg" ) {
              $mods += $mod
       }
}
foreach ( $mod in $mods ) {
       [void] $WebApp.WebConfigModifications.Remove($mod)
}
$webApp.Update()
$webApp.Parent.ApplyWebConfigModifications()




Monday, March 7, 2016

Infopath cannot save the following form. this document library was either renamed or deleted or network problems are preventing the file from being saved

So working with an InfoPath form, you try to publish to SharePoint and get this:

Infopath cannot save the following form. this document library was either renamed or deleted or network problems are preventing the file from being saved

You retry - problem persists! Assuming you don't actually have network issues, the problem is likely that either (a) you didn't install the Desktop Experience (I know, I know) and/or (b) the Windows Themes service isn't running. Turns out, InfoPath needs the D.E. features and that service to work.

In most cases, it will be (a). You can use the system manager to install quickly but you can easily do it from PowerShell:


The command (in case you can't read it) is:

Install-WindowsFeature Desktop-Experience

As noted, once complete, you will have to reboot the server. IF this doesn't work, check the Windows Themes service (it should be set to Automatic and should be started).

Kudos to David Lean on this.

Thursday, March 3, 2016

Using the Upload Document Button outside of the Document Center (SP 2013)

Like me, you've probably wanted to use the Upload Document button from the Document Center in another site type:
While I've done this in 2010, there are some minor changes in 2013 to the script to get it to work. Using the 2010 solutions, you will find that once a page it published, the script will not work!

Here's the actual solution for 2013 - first, create a text file and add the following code (note the URL you have to set - also, I used 'Documents' - specify the proper library name):

<script type="text/javascript">// <![CDATA[
var navBarHelpOverrideKey = "wssmain";
function OpenNewFormUrl(url)
{
var options = {};
SP.SOD.executeFunc('sp.ui.dialog.js', 'SP.UI.ModalDialog.showModalDialog', function() {
SP.UI.ModalDialog.commonModalDialogOpen(url, options, null, null);
});
}
// ]]>
</script>
<div>
   <button onclick="javascript:OpenNewFormUrl(&#39;[URL TO YOUR SITE]/Documents/Forms/upload.aspx&#39;);return false;">
      <nobr>
         <img alt="Upload a Document" src="/_layouts/15/images/uploaddoc.png?rev=23" style="vertical-align: middle;"/>&#160;<span>Upload a Document</span></nobr> </button></div>


Upload the file to a library in SharePoint and copy the link (shortcut). Navigate to a page and add a Content Editor Web Part or Script Web Part - edit the web part settings and paste in the link to the text file. Save the part settings and you are ready to go.

NOTE: Don't edit the CEWP source - SharePoint will 'rewrite' the code and while it might work, more often it doesn't!