Over the past decade, web-based applications have developed to
the point that each user interaction requires very little data to be downloaded
as pages change and refresh. A prime example is Facebook, where each user
interaction (such as the addition of a comment) results in an update of only
that portion of the page, improving performance and response time considerably.
SharePoint is based on a very rich web interface containing lots
of moving parts and lots of customizable areas. As you know the Interweb is
based on a request-response approach where you request a page and get a
response back. The approach is the same whether you update the whole page or
portions of it. The last decade we've seen smart approaches working around this
"problem" using DHTML, JavaScript, AJAX, Update Panels, you name it.
Facebook, which also contains a very rich and dynamic interface, has been
excellent in making a dynamic web interface minimizing the amount of data
downloaded for each user interaction and in this way also increasing the
perceived performance.
Up until now SharePoint (out-of-the-box) has not been that
efficient on this, even though SharePoint 2010 did some improvements. Most
often the whole page has been reloaded for each and every action; this of
course affects all end-users and the perceived performance of SharePoint.
But now, with SharePoint 2013, we have a whole new paradigm
thanks to the Minimal Download Strategy - MDS. In this post I will walk you
through some details of MDS, how to leverage it in your own customizations and
how to successfully adapt your current and future customizations to MDS.
The Minimal Download Strategy (MDS) - an overview
The Minimal Download Strategy is by default enabled on Team
sites, Community sites and a few others in SharePoint 2013.All pages for that
site is rendered "through" the /_layouts/15/start.aspx page. This
page is responsible for loading pages from the site using the MDS. The
start.aspx page has a specific JavaScript object asyncDeltaManager (defined
in start.js). Basically it parses the URL, looks for the # sign and takes the
path following that and dynamically loads that page.
http://polasoft/_layouts/15/Start.aspx#/SitePages/Home.aspx
Subsequent requests to pages are dynamically loaded through the
asyncDeltaManager object. Once a link is clicked it will invoke a method in the
JavaScript object which creates the MDS URL and appends the query string
parameterAjaxDelta=1. A
request is created and downloaded asynchronously and only the "delta"
is returned to the client and assembled and rendered using JavaScript.
How is the delta pages generated?
One of the key things in the MDS implementation is that
SharePoint 2013 contains a new Page class - the DeltaPage. This page
class is the key to generating the full pages or just the deltas. Fortunately
the common pages such as WebPartPage, WikiEditPage, UnsecuredLayoutsPageBase,
LayoutsPageBase etc are inheriting from this page. so most of the out-of-the
box pages works and hopefully your custom application pages as well. This page
class is quite smart it can handle when MDS is not enabled (ie default
rendering) and when MDS is enabled. When MDS is enabled for the site this page
is responsible for creating the delta response. The DeltaPage is also
responsible for handling exceptions such as when the master page is different
(another one or a new version). Every delta request sent using the
asyncDeltaManager has a specific request header - the X-SharePoint header. This header contains information about
the master page, the language and if the page is in read-write or read-only
mode. This header is important since it contains the master page, the version
of the master page etc and SharePoint uses this to determine whether to do a
full reload (if the master page have changed) or not. So if you’re working on a
master page, be prepared for full reloads of the page, at least the first time
you request a page using the modified master page.
Enabling or disabling MDS on a site
First of
all what sites do have the MDS enabled by default? MDS is actually a SharePoint
feature (Name; MDSFeature, Id:
87294C72-F260-42f3-A41B-981A2FFCE37A) which is Web scoped. Some of SharePoint
2013 Site Templates has this feature stapled (for instance Team, Community,
Wiki, Projects, App and Blog sites). The feature is very straightforward - it
toggles the EnableMinimalDownload property
of the SPWeb object.
So you can quite easily yourself turn it off using code (server side or CSOM!!)
or PowerShell. Of course you also use the Site Settings > Site Features to
turn it on or off as well.
The MDS is
not enabled on publishing sites and is (as I understand it) not compatible with
publishing sites, there are a couple of reasons for this, continue to read for
more information
Requirements for MDS
Except enabling MDS it is required for the MDS to work there is
one control that must be placed in the master page - the AjaxDelta control. It should be added to the head section of the master
page. This control is responsible for a couple of things. If the page is a
start/home page it will clear all controls and make sure that the page is
loaded fully and registers the correct scripts.
The PageRenderMode control
There is
one control called PageRenderMode that can be used on a master page, web part page or page layout.
This control has one property called RenderModeType which can have one of two possible
values;Standard or MinimalDownload. If the control is placed on a page and
have the property set to Standard – it will prohibit the page from being
rendered using MDS. If the control is not present or if it’s property is set to
MinimalDownload it can participate in MDS rendering. So this control can be
used on specific (master)pages to prohibit MDS.
1
|
<SharePoint:PageRenderMode runat="server" RenderModeType="MinimalDownload" /> |
A word of
caution here, if you’re using the Design Manager to generate master pages, this
control will automatically be inserted into the generated artifacts.
Another
gotcha here is that even if you have the PageRenderMode control set to
MinimalDownload whenever the publishing features are enabled and you have the
ribbon on the page, specifically when using the PublishingRibbon in your master
page, SharePoint will automagically inject, during runtime, the PageRenderMode
control with the property set to Standard.
How does the delta response look like?
The response returned to the asyncDeltaManager has a specific
format which very much resembles how ASP.NET UpdatePanels work. Each control
that should be re-rendered on a page has it's HTML rendition and all these
renditions are separated by a specific token which has the format:
-deltaboundary-<Guid>-
The Guid is unique (which is the purpose of guids :-) and the
asyncDeltaManager retrieves the current token from the response header called deltaBoundary.
After all
deltas, at the end of the response, is another encoded set of data This data
tells what each delta boundary block is intended for and has the following
format:
content length|type|id|data|
Type identifies what kind of delta data it is; controlDelta is a
standard control, pageTitle the title
of the page,pageRedirect a page redirection etc. There are about ten more different
types. Id identifies the control identifier and data, is the data...
The
asyncDeltaManager takes all this information and assembles the page, so it all
looks fast and neat for the end users
In SharePoint master
pages the AjaxDelta control is directly related to how the Minimal Download
Strategy (MDS) knows which parts of the layout to refresh before the page is
rendered. More specifically, anything not wrapped in an AjaxDelta control will
not refresh between pages of a site with the MDS feature activated.
For example, if you
have some dynamic page element, such as the page title, and it is not wrapped
in an AjaxDelta control, every page on a site with MDS enabled will show the
same title from page to page. This is because the first page routed through
start.aspx causes MDS to cache everything on the page that isn’t wrapped in an
AjaxDelta; every other page will show the same title. On the other hand, if it
were wrapped in an AjaxDelta control, MDS would know it needs to render any differences
from the previously loaded page.
<SharePoint:AjaxDelta ID="DeltaSearch"
BlockElement="true" runat="server">
<asp:ContentPlaceHolder
id="PlaceHolderSearchArea" runat="server">
<SearchWC:SearchBoxScriptWebPart
UseSiteCollectionSettings="true"
EmitStyleReference="false"
ShowQuerySuggestions="true"
ChromeType="None"
UseSharedSettings="true"
TryInplaceQuery="false"
ServerInitialRender="true"
runat="server" />
</asp:ContentPlaceHolder>
</SharePoint:AjaxDelta>
|
Each AjaxDelta control
has a unique ID and an optional attribute BlockElement. When BlockElement is
true the AjaxDelta wraps the control in an HTML <div>;
otherwise it uses a <span>.
- The
newly requested page has a different master page than the current page. This makes complete
sense: requesting a page with a different master page than the current one
means that the most basic structure of the page needs to be updated. These
changes are too fundamental for MDS to handle. Keep your master page
options as simple as possible to avoid this risk.
- The
current master page has been updated since the last page load. Also makes sense for
the same reason mentioned above.
- The
current or requested page contains “non-compliant” content:
- The
page uses the ASP.NET 2.0 framework. The MDS server engine is only able to run its
magic on pages running on ASP.NET 3.5 or later. Hopefully you aren’t
deploying ASP.NET 2.0 pages to SharePoint anymore, but if you are, stop.
No, seriously–stop.
- The
page uses CSS or Javascript files that aren’t registered with the MDS
engine. For
solutions deploying custom mark-up (in custom application pages), you can
make MDS aware of CSS and JavaScript files by using the standard CssLink, CssRegistration,
and ScriptLink server tags. If you aren’t in
the habit of doing this already, see MSDN’s article on modifying SharePoint content
for MDS for
more info.
- The
page contains “illegal” HTML. At
the very least both <script/> and <style/> tags
are considered illegal; as mentioned above, use the server-side CssLink, CssRegistration,
and ScriptLink tags instead. “Illegal” HTML may
cover other conditions that might prevent the MDS engine from correctly
parsing the page. Avoid unclosed block-level tags, missing <head/> or <body/> sections,
etc.
- The
current or requested page contains “non-compliant” controls:
- The
control is not in the MDS engine whitelist. “Whitelisting” is achieved by registering
resources with the SPPageContentManager class,
using the RegisterClientScriptBlock(),
RegisterClientScriptInclude(), RegisterInlineStyle(),
and similar methods. See MSDN’s SPPageContentManager API reference for more details. - The
control assembly is not marked as MDS-compliant. Assemblies that
contain custom controls have to be marked with the Microsoft.SharePoint.WebControls.MdsCompliantAttribute to
alert the server-side MDS engine that they have controls that support
MDS. Reference MSDN’s article on modifying SharePoint content
for MDS for
examples of how this is done.
- The
control’s class doesn’t have the MDS attribute. Server-side control
classes also have to be marked with the MdsCompliantAttribute to
alert the MDS engine that they support it. This should only be done if
all other compliance steps mentioned here have been taken.
As a developer of full-trust farm solutions for SharePoint 2013,
you have a great deal of control over whether or not your custom code and
controls cause MDS to fail.However, if you are developing SharePoint 2013
App Parts for SharePoint-Hosted or Provider-Hosted solutions, the MDS story for
now is bleak. The control used by SharePoint to render embedded App Parts on a
page causes MDS to fail: Every. Single. Time. Not only does it fail,
but the failure appears to be caused by SharePoint’s internals; there’s no
way to resolve this by making App Parts MDS compliant. We dug into the
SharePoint 2013 source using .NET Reflector and discovered that the SPAppIFrame control
used to render App Parts emits a raw <script/> tag using
theHtmlTextWriter class. This makes the SPAppIFrame control
non-MDS compliant this doesn’t leave
many options for Hosted Solution developers for now:
- Use
Apps instead of App Parts.
There’s significant business value in the capability of adding custom,
configurable app logic (i.e. web parts) to SharePoint pages. But if you
can architect your solution to keep your custom logic confined to its own
pages, you have the opportunity to introduce your own “proper”(read:
non-retrofit) SPA behavior by using Angular, Backbone, or another SPA
framework within your app. Developing your own SPA logic reclaims
significant control of application flow and performance; don’t discount
this option just because “the client expects web parts.”
- Avoid
routing requests to non-MDS-compliant pages through start.aspx. For example, if your site
home page contains custom App Parts, any links to that page from your top
navigation, quick links, wiki pages, and external sites should route
directly to the <site>/SitePages/Home.aspx URL
instead of using <site>/, which will cause it to route
through start.aspx. Consider validating all of your navigation
links, and any that contain start.aspx should be replaced
if the link target includes a custom App Part.
- Disable
the MDS feature on your SharePoint web. MDS is packaged as a feature on your SharePoint web,
and it’s easy to disable. This is “the nuclear option”, but for sites with
significant customizations on multiple pages, the overall performance may
very well improve with MDS disabled.
Hope this will help you guy’s cheers… J
Great Post..Appreciate your efforts in putting this together.. lot of blogs and articles on the same but no where i found it is composed completely..
ReplyDelete-PCM
Timely suggestions , Just to add my thoughts , you are interested in a a form , I filled out and esigned a sample version here http://goo.gl/NaIO4J.
ReplyDelete