<?xml version="1.0" encoding="utf-8"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/"><channel><language>en</language><title>Blog posts by Ben Morris</title> <link>https://world.optimizely.com/blogs/Ben-Morris/</link><description></description><ttl>60</ttl><generator>Optimizely World</generator><item> <title>Using Google Mini as an EPiServer search solution</title>            <link>https://world.optimizely.com/blogs/Ben-Morris/Dates/2010/9/Using-Google-Mini-as-an-EPiServer-search-solution/</link>            <description>&lt;p&gt;Google Mini can provide a low-cost alternative to Lucene-based searching in EPiServer. Although its text-based search is simple and powerful, the devil, as ever, is in the detail.&lt;/p&gt; &lt;h2&gt;What Google Mini does&lt;/h2&gt; &lt;p&gt;Google Mini is a stand-alone hardware unit that provides a configurable “Google in a box” on your network. It indexes site content by reading web pages and following links, deciding on page relevancy in much the same way as the real search engine.&lt;/p&gt; &lt;p&gt;A single Google Mini box can be used to provide search for any number of different sites. All the crawled content is kept in a central index and you specify any number of sub-sets of this index as collections, allowing for a rudimentary partitioning your search index. Google Mini also allows you to create different “front-ends”, which are a collection of client settings that include different keyword matches and synonyms.&lt;/p&gt; &lt;p&gt;It’s very easy to get up and running. All you do is point it at a website, wait for the content to be crawled and then start firing requests at it. The Google Mini API is simple enough, relying on a simple RESTful call to the device that can return a set of results as XML. Putting together an API abstraction to format requests and deserialize responses is a pretty trivial development task.&lt;/p&gt; &lt;p&gt;It’s important to bear in mind that Google Mini is still a bit of a “black box”. You can filter your search and adjust the way in which it indexes a site, but you cannot go in and directly tweak any of the indexed content. It merely reports back on what it sees and optimising your EPiServer page output for Google Mini is where the real work lies in an implementation.&lt;/p&gt; &lt;h2&gt;Maximising page relevance&lt;/h2&gt; &lt;p&gt;If you want your search results to make sense then it is incumbent on you to make sure that your page mark-up is optimised for search engines. As this is a Google-based engine, the normal SEO rules apply here. You need to ensure that your &lt;a href=&quot;http://www.ben-morris.com/optimising-html-page-structure-for-search-engine-optimisation&quot;&gt;page structure is optimised for SEO&lt;/a&gt; and that your internal linking distributes page rank appropriately.&lt;/p&gt; &lt;p&gt;The amount of unique content in a page is also important – this is, one of the ways in which Google decides what a page is “really about”. Many page designs use a lot of boiler plate mark-up which is pretty much the same between every page, i.e. a large header, footer and side bar. With this kind of web design the amount of unique content between each page can be a relatively small proportion of the overall content.&lt;/p&gt; &lt;p&gt;One way of getting Google Mini to focus on the relevant content is to selectively render page content for the Google Mini device. You can assign a unique user agent string to the Google Mini so you can detect it when a page loads and choose which parts of the page to render.&lt;/p&gt; &lt;p&gt;Although this can be an effective way of optimising Google Mini indexing do not be tempted to selectively render content for external search engines. Google regards this as a spamming technique and it will penalise your site in the search rankings if it discovers that you’re sending out different content to search engine spiders.&lt;/p&gt; &lt;h2&gt;Property-based search via meta-tags&lt;/h2&gt; &lt;p&gt;Google Mini provides fantastic text-based search complete with all the richness and intelligence you’d expect from Google-based search. However, many websites require a search solution that provides more than just text-based searching. In particular, some level of filtering by specific page properties is often required.&lt;/p&gt; &lt;p&gt;There’s nothing to stop you using FindPagesWithCriteria() in some circumstances, but Google Mini does provide a meta-data catalogue that you can use to support property-based searching. You can publish any EPiServer property as a meta-tag and Google Mini will store these tags, allowing you to specify them as parameters for searches. The tags are also returned as part of the search result information for each page, allowing you to pick up information about a page without having to resort to the EPiServer data factory.&lt;/p&gt; &lt;p&gt;Ideally, you would only want to publish these tags to the Google Mini device rather than exposing details of your EPiServer implementation to normal website visitors. This is easy enough to accomplish given that you can assign a unique user agent string to the Google Mini device.&lt;/p&gt; &lt;p&gt;The Google Mini meta-tag catalogue does have some limitations as it will only store up to 1,000 characters and the only value data types it recognises are strings and dates. It can be used to support most simple property-based search scenarios, but if your requirements are for more sophisticated faceted search then you ought to be looking elsewhere for your search solution.&lt;/p&gt; &lt;h2&gt;Custom sorting via meta-tags&lt;/h2&gt; &lt;p&gt;By default, Google Mini only allows you to sort search results by relevance or the date on which the content was originally indexed. This isn’t enough for more specialised searches that may need to sort results by a particular EPiServer property.&lt;/p&gt; &lt;p&gt;The Google Mini meta-tag catalogue can be used to sort results, but you will have to construct a full result set first and then sort it manually. Given that Google Mini returns a maximum of 100 search results with each call this means making successive calls to the device to build up a large result before you can sort it. Once you’ve sorted the result set you should also consider caching it somewhere rather than suffering the overhead of having to re-construct it for successive pages of results.&lt;/p&gt; &lt;p&gt;This is not an ideal solution – it is, in fact, nothing more than a slightly dirty-feeling work-around. That said, it does work for simple sorting scenarios that do not involve more than a few thousand results. More demanding sorting scenarios may demand a different search technology.&lt;/p&gt; &lt;h2&gt;Crawling meta-data on files in the VPP&lt;/h2&gt; &lt;p&gt;Although Google Mini is very effective at crawling text-based content there is no way for it to pick up any meta-data associated with files in your VPP. It can index image and video files, but will only index the filename. If you have a large body of images and videos that have been described and categorised via file summaries then you will need a work-around to ensure that this information will be incorporated into search.&lt;/p&gt; &lt;p&gt;The solution that we used was to create an &lt;a href=&quot;http://www.ben-morris.com/developing-episerver-page-providers-optimizing-performance&quot;&gt;EPiServer page provider&lt;/a&gt; that reads a VPP and renders a web page for each file that contains the file summary information. These pages are only visible to Google Mini so if a user actually visits the page then they are redirected to the actual resource rather than the page provider page.&lt;/p&gt; &lt;p&gt;Again, this is a work-around, but an effective and flexible way of incorporating file summaries into your search index.&lt;/p&gt; &lt;h2&gt;Duplicates on the master language branch&lt;/h2&gt; &lt;p&gt;One problem that is specific to &lt;a href=&quot;http://www.ben-morris.com/using-google-mini-as-an-episerver-search-solution&quot; style=&quot;color: #000000; text-decoration: none;&quot;&gt;EPiServer and Google Mini&lt;/a&gt; is caused by the URL language selector on the master language branch. Google Mini will regard the following URLs as separate pages, even though the content is exactly the same.&lt;/p&gt; &lt;p&gt;&lt;span class=&quot;code&quot;&gt;www.example.com/mypage&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;code&quot;&gt;www.example.com/&lt;strong&gt;en&lt;/strong&gt;/mypage&lt;/span&gt;&lt;/p&gt; &lt;p&gt;To overcome this problem, Google recommend that you add a link tag specifying the &lt;a rel=&quot;nofollow&quot; href=&quot;http://googlewebmastercentral.blogspot.com/2009/02/specify-your-canonical.html&quot; target=&quot;_blank&quot;&gt;canonical URL&lt;/a&gt; to the page’s header section. Although using a canonical URL can help, and is regarded as good practise in any event, we have found that it is not necessarily enough to guarantee that duplicate results will appear with a Google Mini.&lt;/p&gt; &lt;p&gt;Ultimately, if you want to be sure that duplicate pages on the master language branch will not appear in your results then you will need to filter them out of the Google Mini index – this is easy enough to do in the Google Mini crawl and collection settings.&lt;/p&gt; &lt;h2&gt;Low-cost search, but beware of the implementation time&lt;/h2&gt; &lt;p&gt;A Google Mini box requires a relatively small investment – a single unit costs only &#163;2,400. This is cheaper than any licensed search solution for EPiServer but it does come at the cost of extra development work.&lt;/p&gt; &lt;p&gt;One advantage of a Google Mini implementation is that you will almost certainly be left with a site that is very heavily optimised for search engines. The need to define appropriate page titles and descriptions, think through your internal linking and tweak output for relevancy will pay dividends with your external search.&lt;/p&gt; &lt;p&gt;However, if your search requirements involve complex facets, extensive property-based sorting or more than a few hundred thousand pages then you may need to invest more heavily in your search technology.&lt;/p&gt;</description>            <guid>https://world.optimizely.com/blogs/Ben-Morris/Dates/2010/9/Using-Google-Mini-as-an-EPiServer-search-solution/</guid>            <pubDate>Tue, 28 Sep 2010 16:18:07 GMT</pubDate>           <category>Blog post</category></item><item> <title>Converting EPiServer 6 to use claims-based authentication with WIF</title>            <link>https://world.optimizely.com/blogs/Ben-Morris/Dates/2010/6/Converting-EPiServer-6-to-use-claims-based-authentication-with-WIF/</link>            <description>&lt;p&gt;Claims and federated security are increasingly big news in enterprise architectures that seek to implement single sign-on across different domains and technologies.&lt;/p&gt;  &lt;p&gt;This article describes how to modify EPiServer 6 to delegate authentication to a claims issuer as well as discussing the issues that have to be overcome to make it all hang together.&lt;/p&gt;  &lt;h2&gt;What is claims-based security?&lt;/h2&gt;  &lt;p&gt;Claims-based security is a means of de-coupling the whole process of authentication from applications and services. It’s a different way of looking at authentication – instead of users and roles being defined from a central location, you have the notion of &lt;em&gt;claims &lt;/em&gt;that can be provided by a number of &lt;em&gt;issuers&lt;/em&gt;.&lt;/p&gt;  &lt;p&gt;Claims are &lt;em&gt;statements&lt;/em&gt; made about users – for example their name, group or privilege – and they provide a much more flexible way of describing identity than a role-based model. For example, some claims issuers support the idea of &lt;em&gt;private&lt;/em&gt; user identities, so an application can authenticate users without having to know any personal details about them. Claims effectively de-couple roles from authorisation logic, allowing for more finely-grained permission schemas.&lt;/p&gt;  &lt;p&gt;In claims-based security, applications are no longer responsible for authenticating users and this role is delegated to &lt;em&gt;Issuers&lt;/em&gt;. These issuers are completely separate systems that authenticate users and make claims about them, passing the claims to applications in the form of a signed and trusted token. This approach allows for greater flexibility in security configuration, as an application will expect to receive claims about a user, but they don’t care &lt;em&gt;where &lt;/em&gt;these claims actually come from.&lt;/p&gt;  &lt;p&gt;This gives rise to the notion of &lt;em&gt;federated&lt;/em&gt; security, where users can be authenticated across different domains, organisations and technologies. In the Windows world this is supported by Microsoft’s &lt;a href=&quot;http://www.microsoft.com/windowsserver2008/en/us/ad-main.aspx&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;Active Directory Federation Services&lt;/a&gt;, which allows Windows 2008 Server to act as a &lt;em&gt;federation server &lt;/em&gt;and share identity with other security realms via tokens through a trust relationship.&lt;/p&gt;  &lt;p&gt;The &lt;a href=&quot;http://msdn.microsoft.com/en-us/security/aa570351.aspx&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;Windows Identity Foundation&lt;/a&gt; provides a programming framework that supports issuing and consuming claims in applications. It provides a model that allows ASP.NET applications to be easily converted to use claims-based authentication through HTTP.&lt;/p&gt;  &lt;h2&gt;How does this impact EPiServer?&lt;/h2&gt;  &lt;p&gt;The main impact that claims-based security has on EPiServer is that you are delegating responsibility for authentication and authorisation entirely to another system. EPiServer will not have &lt;em&gt;any&lt;/em&gt; role in creating, managing or authorising users, nor will it have any direct access to any store of users and roles. It just accepts claims that have been created by an issuer and acts on them accordingly.&lt;/p&gt;  &lt;p&gt;The diagram below shows [&lt;em&gt;in grossly simplistic terms&lt;/em&gt;] the current EPiServer security model which involves EPiServer interacting directly with an authentication store via providers:&lt;/p&gt;  &lt;p&gt;&lt;img class=&quot;aligncenter size-full wp-image-659&quot; title=&quot;EPiServer security model without claims&quot; alt=&quot;EPiServer security model without claims&quot; src=&quot;http://www.ben-morris.com/wp-content/library/EPiServer-Security-WithoutClaims.jpg&quot; width=&quot;600&quot; height=&quot;249&quot; /&gt;&lt;/p&gt;  &lt;p&gt;The diagram below illustrates [&lt;em&gt;again, pretty simplistically&lt;/em&gt;] how EPiServer fits in to a claims-based model, where authentication takes place in a separate system that EPiServer does not have any direct access to:&lt;/p&gt;  &lt;p&gt;&lt;img class=&quot;aligncenter size-full wp-image-660&quot; title=&quot;EPiServer security with claims&quot; alt=&quot;EPiServer security with claims&quot; src=&quot;http://www.ben-morris.com/wp-content/library/EPiServer-Security-WithClaims.jpg&quot; width=&quot;600&quot; height=&quot;249&quot; /&gt;&lt;/p&gt;  &lt;p&gt;From a technical point of view, adapting an EPiServer site to claims-based security involves several major changes:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Forms authentication is &lt;em&gt;not&lt;/em&gt; used – it is turned &lt;em&gt;off&lt;/em&gt; in &lt;em&gt;web.config&lt;/em&gt;. &lt;/li&gt;    &lt;li&gt;Authentication takes place much earlier in the HTTP pipeline – a couple of HTTP modules are added to authenticate a user at the start of the page request cycle and re-direct them to an issuer if they are not authenticated. &lt;/li&gt;    &lt;li&gt;The membership and role providers do not have any role to play in authentication – everything is handled by an external claims issuer. &lt;/li&gt; &lt;/ul&gt;  &lt;h2&gt;Setting up EPiServer to use a token service&lt;/h2&gt;  &lt;p&gt;Setting up an &lt;a style=&quot;color: #000000; text-decoration: none&quot; href=&quot;http://www.ben-morris.com/converting-episerver-6-to-use-claims-based-authentication-with-wif&quot;&gt;EPiServer 6 site for claims-based authentication with WIF&lt;/a&gt; only requires a few tweaks of the&lt;em&gt; web.config&lt;/em&gt; file.&lt;/p&gt;  &lt;p&gt;You will need a security token service to connect to and you can mock one up if you have installed the Windows Identity Foundation SDK -&lt;a href=&quot;http://www.ben-morris.com/creating-a-security-token-service-website-using-wif-in-visual-studio&quot; target=&quot;_blank&quot;&gt; this article explains how to set up a simple security token service &lt;/a&gt;using Visual Studio 2008.&lt;/p&gt;  &lt;p&gt;To make an EPiServer application claims aware, a new configuration section needs to be added to the &lt;em&gt;configSections&lt;/em&gt; element:&lt;/p&gt;  &lt;div&gt;   &lt;div style=&quot;border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; max-height: 75px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px&quot;&gt;     &lt;pre style=&quot;border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px&quot; id=&quot;codeSnippet&quot;&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;configSections&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;
  ...
  &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;section&lt;/span&gt; &lt;span style=&quot;color: #ff0000&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;microsoft.identityModel&amp;quot;&lt;/span&gt; &lt;span style=&quot;color: #ff0000&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;Microsoft.IdentityModel.Configuration.MicrosoftIdentityModelSection, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;configSections&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Next, you need to switch off forms authentication and deny access to the site:&lt;/p&gt;

&lt;div&gt;
  &lt;div&gt;
    &lt;pre style=&quot;border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px&quot; id=&quot;codeSnippet&quot;&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;authentication&lt;/span&gt; &lt;span style=&quot;color: #ff0000&quot;&gt;mode&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;None&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;authorization&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;deny&lt;/span&gt; &lt;span style=&quot;color: #ff0000&quot;&gt;users&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;?&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;authorization&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;The two HTTP modules that perform the authentication should be added to the &lt;em&gt;system.webServer\modules&lt;/em&gt; section:&lt;/p&gt;

&lt;div&gt;
  &lt;div style=&quot;border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; max-height: 120px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px&quot;&gt;
    &lt;pre style=&quot;border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px&quot; id=&quot;codeSnippet&quot;&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;system.webServer&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;modules&lt;/span&gt; &lt;span style=&quot;color: #ff0000&quot;&gt;runAllManagedModulesForAllRequests&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;true&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;
    ...
    &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;add&lt;/span&gt; &lt;span style=&quot;color: #ff0000&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;WSFederationAuthenticationModule&amp;quot;&lt;/span&gt; &lt;span style=&quot;color: #ff0000&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;Microsoft.IdentityModel.Web.WSFederationAuthenticationModule, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;add&lt;/span&gt; &lt;span style=&quot;color: #ff0000&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;SessionAuthenticationModule&amp;quot;&lt;/span&gt; &lt;span style=&quot;color: #ff0000&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;Microsoft.IdentityModel.Web.SessionAuthenticationModule, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;modules&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;
  ...
&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;system.webServer&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Next, you configure the Identity Foundation itself by adding a&lt;em&gt; microsoft.identityFramework&lt;/em&gt; element into the end of your configuration section:&lt;/p&gt;

&lt;div&gt;
  &lt;div style=&quot;border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px&quot;&gt;
    &lt;pre style=&quot;border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px&quot; id=&quot;codeSnippet&quot;&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;microsoft.identityModel&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;service&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;audienceUris&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;add&lt;/span&gt; &lt;span style=&quot;color: #ff0000&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;http://EPiServer6Site/&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;audienceUris&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;federatedAuthentication&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;wsFederation&lt;/span&gt; &lt;span style=&quot;color: #ff0000&quot;&gt;passiveRedirectEnabled&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;true&amp;quot;&lt;/span&gt; &lt;span style=&quot;color: #ff0000&quot;&gt;issuer&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;http://SecurityTokenService/&amp;quot;&lt;/span&gt; &lt;span style=&quot;color: #ff0000&quot;&gt;realm&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;http://EPiServer6Site/&amp;quot;&lt;/span&gt; &lt;span style=&quot;color: #ff0000&quot;&gt;requireHttps&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;false&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;/&amp;gt;&lt;/span&gt;
      &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;cookieHandler&lt;/span&gt; &lt;span style=&quot;color: #ff0000&quot;&gt;requireSsl&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;false&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;federatedAuthentication&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;applicationService&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;claimTypeRequired&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;claimType&lt;/span&gt; &lt;span style=&quot;color: #ff0000&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name&amp;quot;&lt;/span&gt; &lt;span style=&quot;color: #ff0000&quot;&gt;optional&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;true&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;/&amp;gt;&lt;/span&gt;
        &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;claimType&lt;/span&gt; &lt;span style=&quot;color: #ff0000&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;http://schemas.microsoft.com/ws/2008/06/identity/claims/role&amp;quot;&lt;/span&gt; &lt;span style=&quot;color: #ff0000&quot;&gt;optional&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;true&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;/&amp;gt;&lt;/span&gt;
      &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;claimTypeRequired&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;applicationService&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;issuerNameRegistry&lt;/span&gt; &lt;span style=&quot;color: #ff0000&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;Microsoft.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;trustedIssuers&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;add&lt;/span&gt; &lt;span style=&quot;color: #ff0000&quot;&gt;thumbprint&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;575BC741AAE8F063DD76615EE8152879B3C0F5EA&amp;quot;&lt;/span&gt; &lt;span style=&quot;color: #ff0000&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;http://SecurityTokenService/&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;/&amp;gt;&lt;/span&gt;
      &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;trustedIssuers&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;issuerNameRegistry&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;service&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;microsoft.identityModel&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Finally, just to demonstrate that claims are really driving authentication, you can disable the membership and role providers by replacing the membership and role declarations in the system.web section with the following:&lt;/p&gt;

&lt;div&gt;
  &lt;div&gt;
    &lt;pre style=&quot;border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px&quot; id=&quot;codeSnippet&quot;&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;system.web&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;
  ...
  &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;membership&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;providers&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;clear&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;providers&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;membership&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;roleManager&lt;/span&gt; &lt;span style=&quot;color: #ff0000&quot;&gt;enabled&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;false&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;providers&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;clear&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;providers&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;roleManager&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;
  ...
&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;system.web&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;This is all you need to do to get EPiServer up and running with claims. When you try to access your site you will be re-directed to your security token service website where you will submit your credentials. Once the security token service has logged you in then you’re re-directed back to EPiServer with a set of claims.&lt;/p&gt;

&lt;h2&gt;Inevitably, there are some catches…&lt;/h2&gt;

&lt;p&gt;On the surface, things work quite smoothly as claims authentication provides an identity object that implements the &lt;em&gt;IPrincipal&lt;/em&gt; interface, so the EPiServer API seems to play nicely with claims-based credentials.&lt;/p&gt;

&lt;p&gt;However, things get more tricky with the EPiServer UI, mainly because EPiServer expects direct access to the authentication store through the role and membership APIs, making a number of direct calls to them. Once role and membership providers have been taken out of the equation then a fair amount of the functionality in the EPiServer UI either becomes redundant or just plain fails.&lt;/p&gt;

&lt;p&gt;The details of how you would solve these UI issues depend very much on the nature and type of claims that your are receiving from your issuer, but there are two main issues to solve.&lt;/p&gt;

&lt;p&gt;Firstly, when assigning access right to content in EPiServer, a call is made to a role provider for a list of all the currently available roles. If you want to be able to assign access rights for content and features to roles that are returned by claims then you will need to create a &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/8fw7xh74.aspx&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;custom role provider&lt;/a&gt; for EPiServer that supplies a list of all the valid roles that your claims issuer is likely to use.&lt;/p&gt;

&lt;p&gt;The exact implementation of this custom role provider would depend on the number of roles, the source of roles and the frequency with which they are likely to change. Whatever the approach, there is no getting away from having to create &lt;em&gt;some &lt;/em&gt;kind of custom role provider to serve a valid list of roles to the EPiServer UI.&lt;/p&gt;

&lt;p&gt;The second issue is that &lt;a style=&quot;color: #000000; text-decoration: none&quot; href=&quot;http://www.ben-morris.com/&quot;&gt;EPiServer&lt;/a&gt; exposes a lot of functionality that is no longer available in a claims-aware application – e.g. creating and managing users and groups. In some cases – such as the log-out button – this functionality will just fail, while in other cases it will fail with some pretty ugly exceptions.&lt;/p&gt;

&lt;p&gt;Again, the solution to this depends on circumstances and your users’ tolerance for a slightly flakey UI. You can resolve this issue either by educating your users (difficult, but straightforward), &lt;a href=&quot;http://world.episerver.com/Blogs/David-Knipe/Dates/2010/5/Customising-the-EPiServer-UI/&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;customising the EPiServer UI&lt;/a&gt; (clever, but risky) or by creating “dummy” custom providers that return empty results for every significant method (dirty, but effective).&lt;/p&gt;

&lt;h2&gt;Summary&lt;/h2&gt;

&lt;p&gt;Although EPiServer does not provide direct support for claims-based security, the fact that its security model is pluggable and closely aligned to ASP.NET’s standard design patterns means that, with a bit of tweaking, you can get an EPiServer-based site to be claims-aware.&lt;/p&gt;

&lt;p&gt;However, the devil is in the detail – or the EPiServer UI – and you will probably need to do some work with custom role and membership providers to deliver a solution. The exact details of these would depend on the nature of the claims that you are receiving and the authentication store that they are coming from.&lt;/p&gt;</description>            <guid>https://world.optimizely.com/blogs/Ben-Morris/Dates/2010/6/Converting-EPiServer-6-to-use-claims-based-authentication-with-WIF/</guid>            <pubDate>Wed, 16 Jun 2010 11:58:40 GMT</pubDate>           <category>Blog post</category></item><item> <title>Implementing Dublin Core meta data for EPiServer pages via a plug-in</title>            <link>https://world.optimizely.com/blogs/Ben-Morris/Dates/2010/2/Implementing-Dublin-Core-meta-data-for-EPiServer-pages-via-a-plug-in/</link>            <description>&lt;p&gt;Dublin Core is in heavy use in the UK public sector – anybody who has had to complete an RFP document for a UK public sector customer will be familiar with questions regarding your proposed CMS platform’s support for it. &lt;/p&gt;  &lt;p&gt;Dublin Core is a meta data standard that is used to describe resources across different platforms and technologies in a way that makes them easy to find. It’s an XML-based resource description format that is used to describe a wide range of resources, including video, images, text and – perhaps most commonly – web pages. &lt;/p&gt;  &lt;p&gt;The Simple Dublin Core Metadata Set (DCMES) is composed of a list of fifteen separate elements which include simple descriptive items such as title, creator, subject, description and creation date. These basic elements have been extended to include a number of other tags and qualified with a set of recommended encoding schemes, such as ISO8601 for date formats. Dublin Core is implemented on web pages as a set of meta tags that conform to the published Dublin Core schema, although the mixture of tags used tends to vary considerably between different sites. &lt;/p&gt;  &lt;p&gt;A typical set of Dublin Core tags look something like the example below:&lt;/p&gt;  &lt;div id=&quot;codeSnippetWrapper&quot;&gt;   &lt;pre style=&quot;border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px&quot; id=&quot;codeSnippet&quot;&gt;&amp;lt;link rel=&lt;span style=&quot;color: #006080&quot;&gt;&amp;quot;schema.DC&amp;quot;&lt;/span&gt; href=&lt;span style=&quot;color: #006080&quot;&gt;&amp;quot;http://purl.org/dc/elements/1.1/&amp;quot;&lt;/span&gt; /&amp;gt;&lt;br /&gt;&amp;lt;meta name=&lt;span style=&quot;color: #006080&quot;&gt;&amp;quot;DC.title&amp;quot;&lt;/span&gt; lang=&lt;span style=&quot;color: #006080&quot;&gt;&amp;quot;en&amp;quot;&lt;/span&gt; content=&lt;span style=&quot;color: #006080&quot;&gt;&amp;quot;Home page&amp;quot;&lt;/span&gt; /&amp;gt;&lt;br /&gt;&amp;lt;meta name=&lt;span style=&quot;color: #006080&quot;&gt;&amp;quot;DC.creator&amp;quot;&lt;/span&gt; content=&lt;span style=&quot;color: #006080&quot;&gt;&amp;quot;Ben Morris&amp;quot;&lt;/span&gt; /&amp;gt;&lt;br /&gt;&amp;lt;meta name=&lt;span style=&quot;color: #006080&quot;&gt;&amp;quot;DC.publisher&amp;quot;&lt;/span&gt; content=&lt;span style=&quot;color: #006080&quot;&gt;&amp;quot;Acme Corporation&amp;quot;&lt;/span&gt; /&amp;gt;&lt;br /&gt;&amp;lt;meta name=&lt;span style=&quot;color: #006080&quot;&gt;&amp;quot;DC.date&amp;quot;&lt;/span&gt; scheme=&lt;span style=&quot;color: #006080&quot;&gt;&amp;quot;ISO8601&amp;quot;&lt;/span&gt; content=&lt;span style=&quot;color: #006080&quot;&gt;&amp;quot;2010-04-23T16:27&amp;quot;&lt;/span&gt; /&amp;gt;&lt;br /&gt;&amp;lt;meta name=&lt;span style=&quot;color: #006080&quot;&gt;&amp;quot;DC.type&amp;quot;&lt;/span&gt; scheme=&lt;span style=&quot;color: #006080&quot;&gt;&amp;quot;DCMIType&amp;quot;&lt;/span&gt; content=&lt;span style=&quot;color: #006080&quot;&gt;&amp;quot;Text&amp;quot;&lt;/span&gt; /&amp;gt;&lt;br /&gt;&amp;lt;meta name=&lt;span style=&quot;color: #006080&quot;&gt;&amp;quot;DC.format&amp;quot;&lt;/span&gt; scheme=&lt;span style=&quot;color: #006080&quot;&gt;&amp;quot;IMT&amp;quot;&lt;/span&gt; content=&lt;span style=&quot;color: #006080&quot;&gt;&amp;quot;text/html&amp;quot;&lt;/span&gt; /&amp;gt;&lt;br /&gt;&amp;lt;meta name=&lt;span style=&quot;color: #006080&quot;&gt;&amp;quot;DC.identifier&amp;quot;&lt;/span&gt; content=&lt;span style=&quot;color: #006080&quot;&gt;&amp;quot;/dublin-core-meta-data-plug-in-for-episerver-pages/&amp;quot;&lt;/span&gt; /&amp;gt;&lt;br /&gt;&amp;lt;meta name=&lt;span style=&quot;color: #006080&quot;&gt;&amp;quot;DC.language&amp;quot;&lt;/span&gt; scheme=&lt;span style=&quot;color: #006080&quot;&gt;&amp;quot;RFC1766&amp;quot;&lt;/span&gt; content=&lt;span style=&quot;color: #006080&quot;&gt;&amp;quot;en&amp;quot;&lt;/span&gt; /&amp;gt;&lt;br /&gt;&amp;lt;meta name=&lt;span style=&quot;color: #006080&quot;&gt;&amp;quot;DC.coverage&amp;quot;&lt;/span&gt; content=&lt;span style=&quot;color: #006080&quot;&gt;&amp;quot;World&amp;quot;&lt;/span&gt; /&amp;gt;&lt;br /&gt;&amp;lt;meta name=&lt;span style=&quot;color: #006080&quot;&gt;&amp;quot;DC.rights&amp;quot;&lt;/span&gt; content=&lt;span style=&quot;color: #006080&quot;&gt;&amp;quot;/terms-and-conditions/&amp;quot;&lt;/span&gt; /&amp;gt;&lt;/pre&gt;

  &lt;br /&gt;&lt;/div&gt;

&lt;p&gt;The content for all of these tags can be easily generated from EPiServer – this post explains a technique for developing an &lt;a style=&quot;color: #000000; text-decoration: none&quot; href=&quot;http://www.ben-morris.com/implementing-dublin-core-meta-data-for-episerver-pages-via-a-plug-in&quot;&gt;EPiServer plug-in&lt;/a&gt; that will automatically insert Dublin Core meta tags to EPiServer pages that can be dropped in to an existing site without requiring any code changes to your site or templates. &lt;/p&gt;

&lt;p&gt;This plug-in works via an http module, which intercepts requests for EPiServer pages immediately after the content has been processed, formats a set of meta tags based on the page’s EPiServer properties and inserts the tags just before the end of the page’s &amp;lt;/HEAD&amp;gt; section. A code sample of the whole thing can be &lt;a href=&quot;http://www.ben-morris.com/wp-content/library/EPiPlugins.DublinCore.zip&quot; target=&quot;_blank&quot;&gt;downloaded from here&lt;/a&gt; (ZIP archive, 7KB), but the following is an explanation of the mechanics.&lt;/p&gt;

&lt;h2&gt;Creating the http module&lt;/h2&gt;

&lt;p&gt;An http module allows you to hook into a number of events that are raised during the http request cycle. The event that we are interested in here is the PostRequestHandlerExecute event, which occurs just after the page has finished execution and the HTML content is ready to be sent back to the browser. &lt;/p&gt;

&lt;p&gt;Creating an http module is pretty straightforward – you create a class that implements the IHttpModule interface and register it in web.config. This interface requires two methods: Init(), where you hook up any events that you want to execute code on, and a Dispose() method to clean up any resources that you have used. &lt;/p&gt;

&lt;p&gt;The code sample below shows a basic module that hooks into the PostRequestHandlerExecute event.&lt;/p&gt;

&lt;div style=&quot;border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px&quot; id=&quot;codeSnippetWrapper&quot;&gt;
  &lt;pre style=&quot;border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px&quot; id=&quot;codeSnippet&quot;&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;using&lt;/span&gt; System;&lt;br /&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;using&lt;/span&gt; System.Web;&lt;br /&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;using&lt;/span&gt; EPiServer;&lt;br /&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;using&lt;/span&gt; EPiServer.Core;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;namespace&lt;/span&gt; EPiPlugins.DublinCore&lt;br /&gt;{&lt;br /&gt;    &lt;span style=&quot;color: #0000ff&quot;&gt;public&lt;/span&gt; &lt;span style=&quot;color: #0000ff&quot;&gt;class&lt;/span&gt; DCHttpModule : IHttpModule&lt;br /&gt;    {&lt;br /&gt;        &lt;span style=&quot;color: #0000ff&quot;&gt;public&lt;/span&gt; &lt;span style=&quot;color: #0000ff&quot;&gt;void&lt;/span&gt; Init(HttpApplication context)&lt;br /&gt;        {&lt;br /&gt;            &lt;span style=&quot;color: #008000&quot;&gt;//* Subscribe to PostRequestHandlerExecute&lt;/span&gt;&lt;br /&gt;            context.PostRequestHandlerExecute += &lt;span style=&quot;color: #0000ff&quot;&gt;new&lt;/span&gt; EventHandler(context_PostRequestHandlerExecute);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        &lt;span style=&quot;color: #0000ff&quot;&gt;public&lt;/span&gt; &lt;span style=&quot;color: #0000ff&quot;&gt;void&lt;/span&gt; context_PostRequestHandlerExecute(&lt;span style=&quot;color: #0000ff&quot;&gt;object&lt;/span&gt; sender, EventArgs e)&lt;br /&gt;        {&lt;br /&gt;            &lt;span style=&quot;color: #008000&quot;&gt;//* Do some work...&lt;/span&gt;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;

  &lt;br /&gt;&lt;/div&gt;

&lt;p&gt;The event handler for the PostRequestHandlerExecute event will have to do the following work: &lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Get the current application context – this will give you access to the Request and Response objects. &lt;/li&gt;

  &lt;li&gt;Check that the current URL refers to an EPiServer page and ignore everything else (note that every request handled by ASP.NET will pass through your http module – this includes javascript files, images and style sheets). &lt;/li&gt;

  &lt;li&gt;Get the PageData object for the current page. &lt;/li&gt;

  &lt;li&gt;Format some Dublin Core meta data on the basis of the PageData object. &lt;/li&gt;

  &lt;li&gt;Filter the out-going response in order to insert the meta data. &lt;/li&gt;

  &lt;li&gt;The basic outline of this event handler will look something like this: &lt;/li&gt;
&lt;/ul&gt;

&lt;div style=&quot;border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px&quot; id=&quot;codeSnippetWrapper&quot;&gt;
  &lt;pre style=&quot;border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px&quot; id=&quot;codeSnippet&quot;&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;public&lt;/span&gt; &lt;span style=&quot;color: #0000ff&quot;&gt;void&lt;/span&gt; context_PostRequestHandlerExecute(&lt;span style=&quot;color: #0000ff&quot;&gt;object&lt;/span&gt; sender, EventArgs e)&lt;br /&gt;{&lt;br /&gt;    &lt;span style=&quot;color: #0000ff&quot;&gt;if&lt;/span&gt; (sender != &lt;span style=&quot;color: #0000ff&quot;&gt;null&lt;/span&gt;)&lt;br /&gt;    {&lt;br /&gt;        &lt;span style=&quot;color: #008000&quot;&gt;//* Get the application reference - this allows us into the HttpContext&lt;/span&gt;&lt;br /&gt;        HttpApplication senderApp = (HttpApplication)sender;&lt;br /&gt;&lt;br /&gt;        &lt;span style=&quot;color: #008000&quot;&gt;//* Only process aspx pages&lt;/span&gt;&lt;br /&gt;        &lt;span style=&quot;color: #0000ff&quot;&gt;if&lt;/span&gt; (senderApp.Context.Request.Url.AbsoluteUri.IndexOf(&lt;span style=&quot;color: #006080&quot;&gt;&amp;quot;.aspx&amp;quot;&lt;/span&gt;, StringComparison.InvariantCultureIgnoreCase) &amp;gt;= 0))&lt;br /&gt;        {&lt;br /&gt;            &lt;span style=&quot;color: #008000&quot;&gt;//* Try to get a page reference from the URL&lt;/span&gt;&lt;br /&gt;            PageReference currentPageRef = PageReference.ParseUrl(senderApp.Context.Request.Url.AbsoluteUri);&lt;br /&gt;&lt;br /&gt;            &lt;span style=&quot;color: #008000&quot;&gt;//* If there&#39;s no PageReference then this is not a request for an EPiServer page, so ignore it&lt;/span&gt;&lt;br /&gt;            &lt;span style=&quot;color: #0000ff&quot;&gt;if&lt;/span&gt; (currentPageRef != PageReference.EmptyReference)&lt;br /&gt;            {&lt;br /&gt;                &lt;span style=&quot;color: #008000&quot;&gt;//* Fetch the page data&lt;/span&gt;&lt;br /&gt;                PageData thisPage = DataFactory.Instance.GetPage(currentPageRef);&lt;br /&gt;&lt;br /&gt;                &lt;span style=&quot;color: #0000ff&quot;&gt;if&lt;/span&gt; (thisPage != &lt;span style=&quot;color: #0000ff&quot;&gt;null&lt;/span&gt;)&lt;br /&gt;                {&lt;br /&gt;                    &lt;span style=&quot;color: #008000&quot;&gt;//* We have page data - format some Dublin Core tags based on the page data&lt;/span&gt;&lt;br /&gt;                    &lt;span style=&quot;color: #0000ff&quot;&gt;string&lt;/span&gt; tags = FormatTags(thisPage);&lt;br /&gt;&lt;br /&gt;                    &lt;span style=&quot;color: #008000&quot;&gt;//* Apply the DCStream filter to the response and it will insert the Dublin Core meta tags&lt;/span&gt;&lt;br /&gt;                    senderApp.Context.Response.Filter = &lt;span style=&quot;color: #0000ff&quot;&gt;new&lt;/span&gt; DCStream(senderApp.Context.Response.Filter, tags);&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;

  &lt;br /&gt;&lt;/div&gt;

&lt;div id=&quot;codeSnippetWrapper&quot;&gt;&amp;#160;&lt;/div&gt;

&lt;h2&gt;Creating a stream wrapper class to filter the content&lt;/h2&gt;

&lt;p&gt;Note that at the end of the PostRequestHandlerExecute event we set the Filter property of the current Response object to a new instance of a class called DCStream. This is where we wrap the http response stream into a custom object that allows us to modify the entire response before it goes to the client. &lt;/p&gt;

&lt;p&gt;The DCStream class is a wrapper around the Stream object that manages an internal representation of the response stream, inserting the Dublin Core tags via an over-write of the Write() method as shown below:&lt;/p&gt;

&lt;div style=&quot;border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px&quot; id=&quot;codeSnippetWrapper&quot;&gt;
  &lt;pre style=&quot;border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px&quot; id=&quot;codeSnippet&quot;&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;public&lt;/span&gt; &lt;span style=&quot;color: #0000ff&quot;&gt;override&lt;/span&gt; &lt;span style=&quot;color: #0000ff&quot;&gt;void&lt;/span&gt; Write(&lt;span style=&quot;color: #0000ff&quot;&gt;byte&lt;/span&gt;[] buffer, &lt;span style=&quot;color: #0000ff&quot;&gt;int&lt;/span&gt; offset, &lt;span style=&quot;color: #0000ff&quot;&gt;int&lt;/span&gt; count)&lt;br /&gt;{&lt;br /&gt;    &lt;span style=&quot;color: #0000ff&quot;&gt;string&lt;/span&gt; strBuffer = System.Text.UTF8Encoding.UTF8.GetString(buffer, offset, count);&lt;br /&gt;&lt;br /&gt;    &lt;span style=&quot;color: #008000&quot;&gt;//* Look for the closing HEAD tag&lt;/span&gt;&lt;br /&gt;    &lt;span style=&quot;color: #0000ff&quot;&gt;int&lt;/span&gt; insertionPoint = strBuffer.IndexOf(&lt;span style=&quot;color: #006080&quot;&gt;&amp;quot;&amp;lt;/head&amp;gt;&amp;quot;&lt;/span&gt;, StringComparison.InvariantCultureIgnoreCase);&lt;br /&gt;    &lt;span style=&quot;color: #0000ff&quot;&gt;if&lt;/span&gt; (insertionPoint &amp;gt;= 0)&lt;br /&gt;    {&lt;br /&gt;        &lt;span style=&quot;color: #008000&quot;&gt;//* Add the Dublin Core tags in to the content&lt;/span&gt;&lt;br /&gt;        strBuffer = strBuffer.Insert(insertionPoint, _DCTags);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style=&quot;color: #008000&quot;&gt;//* Look for the closing HTML tag&lt;/span&gt;&lt;br /&gt;    &lt;span style=&quot;color: #0000ff&quot;&gt;if&lt;/span&gt; (strBuffer.IndexOf(&lt;span style=&quot;color: #006080&quot;&gt;&amp;quot;&amp;lt;/html&amp;gt;&amp;quot;&lt;/span&gt;, StringComparison.InvariantCultureIgnoreCase) &amp;lt; 0)&lt;br /&gt;    {&lt;br /&gt;        _ResponseHtml.Append(strBuffer);&lt;br /&gt;    }&lt;br /&gt;    &lt;span style=&quot;color: #0000ff&quot;&gt;else&lt;/span&gt;&lt;br /&gt;    {&lt;br /&gt;        &lt;span style=&quot;color: #008000&quot;&gt;//* Transform the response and write it back out&lt;/span&gt;&lt;br /&gt;        _ResponseHtml.Append(strBuffer);&lt;br /&gt;        &lt;span style=&quot;color: #0000ff&quot;&gt;string&lt;/span&gt; finalHtml = _ResponseHtml.ToString();&lt;br /&gt;        &lt;span style=&quot;color: #0000ff&quot;&gt;byte&lt;/span&gt;[] data = System.Text.UTF8Encoding.UTF8.GetBytes(finalHtml);&lt;br /&gt;        _ResponseStream.Write(data, 0, data.Length);&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;

  &lt;br /&gt;&lt;/div&gt;

&lt;div id=&quot;codeSnippetWrapper&quot;&gt;
  &lt;br /&gt;&lt;/div&gt;

&lt;h2&gt;Adding your http module to web.config&lt;/h2&gt;

&lt;p&gt;To get your website to pick up the http module you need to add a reference to it to your web project and then add a declaration into the system.webServer/modules section of your web.config file. This declaration will look like this:&lt;/p&gt;

&lt;div id=&quot;codeSnippetWrapper&quot;&gt;
  &lt;pre style=&quot;border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px&quot; id=&quot;codeSnippet&quot;&gt;&amp;lt;add name=”DCHttpModule” type=”EPiPlugins.DublinCore.DCHttpModule, EPiPlugins.DublinCore” /&amp;gt;&lt;/pre&gt;

  &lt;br /&gt;&lt;/div&gt;

&lt;h2&gt;Configuration&lt;/h2&gt;

&lt;p&gt;Not every field in the &lt;a style=&quot;color: #000000; text-decoration: none&quot; href=&quot;http://www.ben-morris.com/implementing-dublin-core-meta-data-for-episerver-pages-via-a-plug-in&quot;&gt;Dublin Core&lt;/a&gt; set has a direct equivalent in the EPiServer PageData object, so you will need to map some of the fileds onto EPiServer page properties. You may want to map the&amp;#160; Dublin Core “description” element onto a specific EPiServer property that will be present on all EPiServer pages, or assert a particular copyright message for the “rights” element for every page. &lt;/p&gt;

&lt;p&gt;There are a number of ways to implement this kind of configuration – I have used a custom configuration section in my code example that lets you define your own section in the web.config file. &lt;/p&gt;

&lt;h2&gt;Code sample&lt;/h2&gt;

&lt;p&gt;You can download a full working sample of the code from &lt;a href=&quot;http://www.ben-morris.com/wp-content/library/EPiPlugins.DublinCore.zip&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt; (ZIP archive, 7KB). &lt;/p&gt;

&lt;p&gt;Bear in mind that this code is a proof of concept rather than a match-fit piece of production code. &lt;/p&gt;

&lt;p&gt;Note that the references for the sample project are set to EPiServer 6 DLLs (v 6.0.530), but it works on EPiServer 5 too.&lt;/p&gt;</description>            <guid>https://world.optimizely.com/blogs/Ben-Morris/Dates/2010/2/Implementing-Dublin-Core-meta-data-for-EPiServer-pages-via-a-plug-in/</guid>            <pubDate>Fri, 12 Feb 2010 13:00:00 GMT</pubDate>           <category>Blog post</category></item><item> <title>Social Media Gadget for EPiServer 6 CTP2</title>            <link>https://world.optimizely.com/blogs/Ben-Morris/Dates/2009/11/Social-Media-Gadget-for-EPiServer-6-CTP2/</link>            <description>&lt;p&gt;Here’s my entry for the EPiServer gadget contest.&lt;/p&gt;  &lt;p&gt;It’s a social media gadget – you can use it to track what’s being said about your site, brand or business through a number of different channels, including Twitter, Google blogs search, Google news search and Flickr.&lt;/p&gt;  &lt;p&gt;It’s designed to be as easy as possible to set up and use. It gets feeds from the public methods from the Twitter, Google and Flickr APIs so you don’t have to mess around entering API keys to get it to work. You just enter a key phrase in the setup screen and you’re away.&lt;/p&gt;  &lt;p&gt;&lt;img title=&quot;Gadget example: Twitter&quot; style=&quot;border-top-style: none; border-right-style: none; border-left-style: none; border-bottom-style: none&quot; alt=&quot;Gadget example: twitter&quot; src=&quot;http://www.ben-morris.com/wp-content/library/bm_gadget_1.JPG&quot; border=&quot;0&quot; /&gt;&lt;/p&gt;  &lt;p&gt;&lt;img title=&quot;Gadget example: Google blogs&quot; style=&quot;border-top-style: none; border-right-style: none; border-left-style: none; border-bottom-style: none&quot; alt=&quot;Gadget example: Google blogs&quot; src=&quot;http://www.ben-morris.com/wp-content/library/bm_gadget_2.JPG&quot; border=&quot;0&quot; /&gt;&lt;/p&gt;  &lt;p&gt;&lt;img title=&quot;Gadget example: Flickr&quot; style=&quot;border-top-style: none; border-right-style: none; border-left-style: none; border-bottom-style: none&quot; alt=&quot;Gadget example: Flickr&quot; src=&quot;http://www.ben-morris.com/wp-content/library/bm_gadget_3.JPG&quot; border=&quot;0&quot; /&gt;&lt;/p&gt;  &lt;h2&gt;Installing the gadget&lt;/h2&gt;  &lt;p&gt;I have put together an installer that can be used in the EPiServer Deployment Centre. It will install all the necessary files in an EPiServer 6 CTP 2 website as well as adding in the necessary entry to web.config.&lt;/p&gt;  &lt;p&gt;The installer can be downloaded from &lt;a href=&quot;http://www.ben-morris.com/wp-content/library/SocialMediaGadget.zip&quot;&gt;here&lt;/a&gt; (zip archive, 42kb).&lt;/p&gt;  &lt;p&gt;The source code is also freely available - setup instructions are included in a readme.txt file in the root of the project.&lt;/p&gt;  &lt;p&gt;The source code lives &lt;a href=&quot;http://www.ben-morris.com/wp-content/library/SocialMediaGadgetSource.zip&quot;&gt;here&lt;/a&gt; (zip archive, 90kb).&lt;/p&gt;</description>            <guid>https://world.optimizely.com/blogs/Ben-Morris/Dates/2009/11/Social-Media-Gadget-for-EPiServer-6-CTP2/</guid>            <pubDate>Mon, 09 Nov 2009 15:20:23 GMT</pubDate>           <category>Blog post</category></item><item> <title>Developing EPiServer page providers: optimizing performance</title>            <link>https://world.optimizely.com/blogs/Ben-Morris/Dates/2009/10/Developing-EPiServer-page-providers-optimizing-performance/</link>            <description>&lt;p&gt;The how-to of &lt;a style=&quot;color: #000000; text-decoration: none&quot; href=&quot;http://www.bombaycrow.com/web_development_asp_net/episerver_page_providers_optimizing_performance/&quot; target=&quot;_blank&quot;&gt;EPiServer page providers&lt;/a&gt; is covered in a variety of places - the best place to start is EPiServer&#39;s &lt;a href=&quot;http://world.episerver.com/en/Articles/Items/Introducing-Page-Providers/&quot; target=&quot;_blank&quot;&gt;white paper&lt;/a&gt; on the subject which contains an XML-based page provider sample. It all looks simple enough from the outset, but it&#39;s only once you start developing implementations for &amp;quot;real-life&amp;quot; data sources that you realise how much coding is involved in a page provider implementation. Given that the feature is relatively new, there doesn&#39;t appear to be too much explanation over what really goes on under the hood and how to develop with efficiency and scalability in mind. &lt;/p&gt;  &lt;p&gt;Having developed providers for relatively large (10,000+ records) data sources, the following are some suggestions for things to bear in mind when developing your page provider. &lt;/p&gt;  &lt;h2&gt;Understanding what EPiServer caches - and what it doesn&#39;t &lt;/h2&gt;  &lt;p&gt;EPiServer relies very heavily on the cache for performance, but it&#39;s important to understand when EPiServer uses the cache and when it will attempt to query your provider&#39;s data source. Once you have constructed a page in your provider&#39;s GetLocalPage() method it&amp;#160; will be placed in the EPiServer page cache and served from memory from then on. However, there are still a number of instances where you will need to refer to the underlying data source - this happens more often than you might think: &lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;EPiServer caches page content, but it does not cache the content structure, i.e. the arrangement of parent and child pages. This means that the structure is constantly re-queried as you access pages, even if the page content is sitting in the page cache. &lt;/li&gt;    &lt;li&gt;If you are looking at a page in edit mode then EPiServer does not retrieve the cached version of a page - it constructs the page from scratch every time. &lt;/li&gt;    &lt;li&gt;If you want to provide property-based search on your page provider then you will have to implement FindPagesFromCriteria() yourself and plumb the criteria directly into your data source. &lt;/li&gt;    &lt;li&gt;Any page updates will, of course, have to be routed back to your data source. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Despite the aggressive page caching, EPiServer does reference the data source for pages pretty regularly - i.e. every time you show a menu or do a search you will be hitting the data. This is worth bearing in mind if you access your data source via a relatively expensive operation such as a web service method. &lt;/p&gt;  &lt;h2&gt;The importance of an optimised data store &lt;/h2&gt;  &lt;p&gt;Given the fact that a page provider requires constant access to the data source, it&#39;s worth caching the data in a structure that is optimised for the kinds of search operations that EPiServer will perform on it. The structure of your cached data is vital for effective provider performance - it is worth doing some performance tests to ensure that you&#39;ve got the optimum structure for the following types of page search (in descending order of frequency): &lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Searching for a page based on a page reference - this is by far the most common &lt;/li&gt;    &lt;li&gt;Searching for a page based on its parent&#39;s page reference &lt;/li&gt;    &lt;li&gt;Finding a page based on its GUID &lt;/li&gt;    &lt;li&gt;Property-based searches using FindPagesWithCriteria() - if you&#39;re implementing search. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;For a very large data set, my solution was to cache the data source by encapsulating the underlying data for a page in a class and using a generic dictionary to store the data, with a PageReference being used for the key, i.e.Dictionary&amp;lt;PageReference, MyPageClass&amp;gt;. This structure provides for super-fast searches pages based on a PageReference, while other, less frequent searches can be carried out in reasonable time using Linq. &lt;/p&gt;  &lt;p&gt;Caching your data source in an optimised data structure does break the direct link between EPiServer and the data source, but in cases with large amounts of page data served by slow interfaces it is pretty necessary. You are also creating processing overhead when you create your cache - this can be mitigated by caching the structure and refreshing it periodically through a scheduled task. &lt;/p&gt;  &lt;h2&gt;GUIDs and unique IDs &lt;/h2&gt;  &lt;p&gt;In order to support EPiServer&#39;s internal linking you will have to maintain a permanent mapping between each page served by your provider, a unique integer-based ID and a unique GUID. If your data source provides the ID and GUID values then you&#39;re in luck, otherwise you will have to develop a mechanism that creates these unique ID and GUID values and persists them against a page. &lt;/p&gt;  &lt;p&gt;There are no short-cuts to creating a GUID for every page. The EPiServer community has suggested a &lt;a href=&quot;http://labs.episerver.com/en/Blogs/Allan/Dates/112230/8/Building-your-own-Page-Provider-Northwind/&quot; target=&quot;_blank&quot; rel=&quot;nofollow&quot;&gt;Guid-less provider&lt;/a&gt; as a solution to creating GUIDs for every page, but given that this involves hacking the bits in a GUID it is not recommended for live systems as it undermines the whole point of GUIDs - i.e. that they should be &lt;em&gt;unique&lt;/em&gt;. &lt;/p&gt;  &lt;p&gt;This requirement for persisting ID and GUID values makes the idea of a pattern based on an optimised data structure even more attractive on performance grounds. Ultimately, you are likely to be storing these values in a database table, so caching them in memory through your optimised page structure will save you an untold number of unnecessary data reads whenever EPiServer tries to look up a GUID on the basis of a page ID and vice versa. &lt;/p&gt;  &lt;h2&gt;Cache the page references, not the IDs &lt;/h2&gt;  &lt;p&gt;The golden rule with page providers is to always work with PageReference objects, never with the raw integer-based ID values. EPiServer constructs a page reference from a combination of the provider name and unique identifier for the provider - the ID value itself is not unique across a website. &lt;/p&gt;  &lt;p&gt;If you want to compare page identifiers then you must use the base class&#39;s ConstructPageReference() helper method to form a PageReference before performing the comparison. The over-head of always having to construct a PageReference may appear small, but over thousands of repetitive operations it does start to add up. It makes a lot of sense to cache the PageReference for each individual page to save yourself countless method calls. &lt;/p&gt;  &lt;h2&gt;Consider providing read-only access &lt;/h2&gt;  &lt;p&gt;Adding support for creating, updating and deleting content doesn&#39;t necessarily have to impact on the performance of your provider. After all, page updates are comparitively rare operations so you can afford to suffer a performance hit on updates in order to maximise the performance of read operations. &lt;/p&gt;  &lt;p&gt;That said, there&#39;s no point writing more code than you really have to. In order to save yourself the development overhead of writing in the plumbing for updating your data source it&#39;s worth taking a long, hard look at whether or not you really need to provide data updates through EPiServer. The key question here is what role is EPiServer playing in your information architecture, i.e. is it there primarily to publish web content? Most optimisation scenarios don&#39;t necessarily need a two-way page provider integration as other systems take responsibility for managing the life cycle of of the underlying content. &lt;/p&gt;  &lt;h2&gt;Security descriptors &lt;/h2&gt;  &lt;p&gt;EPiServer&#39;s XML Page Provider sample contains an interesting custom security descriptor pattern. This allows the security settings for each page to be set by the data source and passed in to each individual PageData object when they are created. &lt;/p&gt;  &lt;p&gt;Managing the security settings for each individual page in your provider can be quite an overhead. If an individual page does not have an ISecurityDescriptor object defined for it then it should check the parent page for the security information. &lt;/p&gt;  &lt;p&gt;This overhead may be unavoidable, but if you are applying the same security settings across every page in your provider then it is worth caching a custom security descriptor in your provider and applying it to every page. This does provide a considerable performance boost as you are not having to do the work of checking parent pages to find and apply security settings. &lt;/p&gt;  &lt;h2&gt;Making life easier for editors &lt;/h2&gt;  &lt;p&gt;When you are serving up thousands of pages in flat, single-level structure, this can provide real performance issues for content editors. When you click on a node in EPiServer, it will query the structure below that node &lt;em&gt;and&lt;/em&gt; for the level below that - which is quite a lot of work when you have 10,000 pages. If a user accidentally clicks on a node containing thousands of provider pages then they will have a long wait on their hands while EPiServer populates the page tree. &lt;/p&gt;  &lt;p&gt;This does call for some automatic sorting for your provider content if you are serving up more than 500 pages through a provider. If you are constructing a cached content structure then you can also write in a system of category pages for the provider - sorting pages into at least two levels in this way will help to protect your content editors from some very frustrating load times. &lt;/p&gt;  &lt;h2&gt;The caveat - search &lt;/h2&gt;  &lt;p&gt;Finally, a warning: EPiServer&#39;s text-based search does not work with page providers. This makes sense when you consider how EPiServer&#39;s search works, but it does have a big impact on your site. If you are going to make heavy use of page providers then you will also have to consider implementing a third party search solution if you want your provider content to be included in a site-wide text search. Spider-based solutions such as Google Mini will do the job here, but you are adding cost and complexity to your project.&lt;/p&gt;</description>            <guid>https://world.optimizely.com/blogs/Ben-Morris/Dates/2009/10/Developing-EPiServer-page-providers-optimizing-performance/</guid>            <pubDate>Mon, 12 Oct 2009 15:26:22 GMT</pubDate>           <category>Blog post</category></item><item> <title>Adding new languages to EPiServer 5</title>            <link>https://world.optimizely.com/blogs/Ben-Morris/Dates/2009/10/Adding-new-languages-to-EPiServer-5/</link>            <description>&lt;p&gt;We’ve recently run into problems with adding the less commonly-used language and locale combinations on an EPiServer installation. How do you add a new language to EPiServer 5 if it doesn’t appear in the list of available languages?&lt;/p&gt;  &lt;p&gt;EPiServer takes the list of the languages that you can enable for a site from the languages that are installed on the host operating system. This can be a problem as the available languages can vary between different machines - for example, Indian English (en-IN) is shipped with Vista but not with Windows 2003 or XP. The big catch is that if you have a language enabled in your EPiServer database which is not installed on your target machine then EPiServer will throw an exception on start-up, which will pull your whole site down.&lt;/p&gt;  &lt;p&gt;If you want to add a new language to EPiServer then you will have to install it on your operating system. This can be done via the &lt;em&gt;CultureAndRegionInfoBuilder&lt;/em&gt; class in &lt;em&gt;System.Globalization. &lt;/em&gt;This class allows you to create a new language from scratch or by copying it from an existing language, although you will have to run the code in the context of an Administrator account for it to work. &lt;/p&gt;  &lt;p&gt;The code sample below shows how CultureAndRegionInfoBuilder can be used to create and register a new language based upon an existing language – in this case creating Hong Kong English (en-HK) from UK English (en-GB). Note that you’ll need a reference to sysglobl.dll in your project for this to compile.&lt;/p&gt;  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; CreateCulture()
{
    &lt;span class=&quot;rem&quot;&gt;//* Get the base culture and region information&lt;/span&gt;
    CultureInfo cultureInfo = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; CultureInfo(&lt;span class=&quot;str&quot;&gt;&amp;quot;en-GB&amp;quot;&lt;/span&gt;);
    RegionInfo regionInfo = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; RegionInfo(cultureInfo.Name);

    &lt;span class=&quot;rem&quot;&gt;//* Create the a locale for en-HK&lt;/span&gt;
    CultureAndRegionInfoBuilder cultureAndRegionInfoBuilder = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; CultureAndRegionInfoBuilder(&lt;span class=&quot;str&quot;&gt;&amp;quot;en-HK&amp;quot;&lt;/span&gt;, CultureAndRegionModifiers.None);

    &lt;span class=&quot;rem&quot;&gt;//* Load the base culture and region information&lt;/span&gt;
    cultureAndRegionInfoBuilder.LoadDataFromCultureInfo(cultureInfo);
    cultureAndRegionInfoBuilder.LoadDataFromRegionInfo(regionInfo);

    &lt;span class=&quot;rem&quot;&gt;//* Set the culture name&lt;/span&gt;
    cultureAndRegionInfoBuilder.CultureEnglishName = &lt;span class=&quot;str&quot;&gt;&amp;quot;English (Hong Kong)&amp;quot;&lt;/span&gt;;
    cultureAndRegionInfoBuilder.CultureNativeName = &lt;span class=&quot;str&quot;&gt;&amp;quot;English (Hong Kong)&amp;quot;&lt;/span&gt;;

    &lt;span class=&quot;rem&quot;&gt;//* Register with your operating system&lt;/span&gt;
    cultureAndRegionInfoBuilder.Register();

}&lt;/code&gt;&lt;/pre&gt;
&lt;style type=&quot;text/css&quot;&gt;&lt;![CDATA[

.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, &quot;Courier New&quot;, courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }]]&gt;&lt;/style&gt;

&lt;p&gt;Once you’ve run this code, fire up EPiServer in Admin mode, select &lt;em&gt;Manage Web Site languages&lt;/em&gt; from the Config tab, click on &lt;em&gt;Add Language&lt;/em&gt; and your new locale will be ready to use.&lt;/p&gt;


&lt;style type=&quot;text/css&quot;&gt;&lt;![CDATA[

.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, &quot;Courier New&quot;, courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }]]&gt;&lt;/style&gt;</description>            <guid>https://world.optimizely.com/blogs/Ben-Morris/Dates/2009/10/Adding-new-languages-to-EPiServer-5/</guid>            <pubDate>Fri, 02 Oct 2009 19:20:37 GMT</pubDate>           <category>Blog post</category></item></channel>
</rss>