Wednesday, September 17, 2014

Tip: HowTo mitigate impact of IE8/IE9 style-tag limit

Many organizations still have IE8 or IE9 as standard browser installed on their employee workstations. Internet Explorer versions before IE10 have an hard boundary on the maximum number of stylelink imports that are applied, namely 31 (see Microsoft Support: 'A webpage that uses CSS styles does not render correctly in Internet Explorer'). Imported link-entries beyond that maximum are effectively ignored in the IE8/IE9 output rendering. This results in missing a part of the applied CSS-styling, and different rendering in IE8/IE9 compared to other browsers (FireFox, Chrome, Safara, IE10/11). The limit of 31 seems large enough, or stated differently: that you would need more than 31 seems ridiculous and unmanageable. But be aware that in the concept of SharePoint, content editors compose functional experiences by placing multiple and mutual independent webparts on SharePoint content pages. These webparts - common-of-the-shelf (Microsoft, any from the large SharePoint community), or custom build - are self-contained, also for their CSS styling. Also the standard SharePoint:CssLink already adds (consumes) 4 css-link imports to the generated page html. So when multiple webparts added to a page, the limit of 31 link-entries in the total page html can certainly be exceeded.
The IE8/IE9 link-limit is an hard number, not possible to increase that. If it is not yet possible or not planned for an organization to migrate to a later IE version (or another browser), you must apply an approach to mitigate the impact of the link-limit. For a part this can be achieved by collapsing multiple link-references within one 'style' island in the outputted html. IE8/IE9 regards plus applies that as only one single style element, and this way you can have multiple link-imports that together only consume 1 of the 31 available stylelink-slots.
Example:
Replace:
<SharePoint:CssRegistration Name="<%$SPUrl:~SiteCollection/Style Library/css/cssfile1.css%>" runat="server"/> <SharePoint:CssRegistration Name="<%$SPUrl:~SiteCollection/Style Library/css/cssfile2.css%>" runat="server"/> ...
Into:
<style type="text/css"> <!-- @import url("../../cssfile1.css"); @import url("../../cssfile2.css"); ... --> </style>
This approach is not the silver bullet to 100% circumvent the hard-imposed IE8/IE9 style-tag limit, but it might save you just sufficiently on occupied stylelink slots to leave sufficient slots for the COTS webparts placed on a page. This was so for myself in a customer project with a COTS SharePoint-based product implementation.
Note:
It is also good to realize that IE8/IE9 emulation modus in IE10 and later, does not impose the link limit. And therefore on this aspect the IE8/IE9 emulation will be different than browsing from real IE8/IE9 browsers.

Friday, September 5, 2014

PowerShell to repeatedly provision SharePoint master and config data

The ease of creating and maintaining SharePoint lists also makes them a good option for application configuration. As example, in one application I applied SharePoint list as the configuration storage for task types specification, in another as the configuration storage of the specifications for BCS invocations via a generic BDC model. However, as easy it is to create a list; so it is also to delete one including the configuration contents. In particular in the development phase, with repeated solution deployment and feature de- and reactivation, typically the configuration list and thus its contents get deleted.
To cope with this, I utilize PowerShell to refill the list with the desired configurations. And the same PowerShell scripts are also of use for transition of the application from development landscape to QA, and ultimate to production.
Example:
# script Clear # Fill Configuration $webApp = “<url>" $ApplicationConfigList="/Lists/ApplicationConfiguration"   # functions   function X-CheckItemNotExists($list, $itemTitle) {    $camlQuery =       "<Where>          <Eq>             <FieldRef Name='Title' />             <Value Type='Text'>" + $itemTitle + "</Value>          </Eq>        </Where>"    $spQuery = new-object Microsoft.SharePoint.SPQuery    $spQuery.Query = $camlQuery    $spQuery.RowLimit = 1    $destItemCollection = $list.GetItems($spQuery)    return $destItemCollection.Count -eq 0 }   # Initialization   $spWeb = Get-SPWeb $webApp   # (Re)fill the Application Config Settings   $ApplicationConfigSettings = @{    "0" = @("<config-item title>", "AovpGetPerson ", "{0,8:D8}{1,30: 30}", "<SAP-system-ID>");    "1" = @("< config-item title>", "CrmGetCustomer", "{0,8:D8}{1,8:D8}", "<Oracle-system-ID>") }                                $spApplicationConfigList = $spWeb.GetList($ApplicationConfigList) foreach ($array in $ ApplicationConfigSettings.values) {    if (X-CheckItemNotExists -list $spApplicationConfigList -itemTitle $array[0].ToString())    {       $spApplicationConfigItem = $spApplicationConfigList.AddItem()       $spApplicationConfigItem["JsonMethodName"] = $array[0].ToString()       $spApplicationConfigItem["GenericModuleMethodName"] = $array[1].ToString()       $spApplicationConfigItem["CallInputParamsFormat"] = $array[2].ToString()        $spApplicationConfigItem["ExternalSystemAlias"] = $array[3].ToString()          $spApplicationConfigItem.Update()    } }    # Release   $spWeb.Dispose()