Blog posts by K Khan 2024-03-22T10:27:12.0000000Z/blogs/K-Khan-/Optimizely WorldTop tip: Better, do not save EPiServer.Foms submissions for sensitive data/blogs/K-Khan-/Dates/2024/3/toptip-stop-indexing-users-uploaded-files/2024-03-22T10:27:12.0000000Z<p><span>If your website utilizes EPiServer.Forms and includes forms where users can upload files, there is a significant probability that the Find/Search Indexing Job will also index those files. Consequently, these files may become accessible through searches facilitated by Find. Editors navigating the Editor area may encounter these files when searching for images, potentially leading to public availability of search results also depending on implementations. To address this issue, a straightforward solution is to cease indexing user-uploaded files. One possible approach to prevent the indexing of uploaded files from forms is outlined in the code below.</span></p>
<pre class="language-csharp"><code>ContentIndexer.Instance.Conventions.ForInstancesOf<IContentMedia>().ShouldIndex(x =>
_contentLoader.GetAncestors(documentFileBase.ParentLink).Select(x=>x.Name).Contains( EPiServer.Forms.Constants.FileUploadFolderName));
</code></pre>
<p>This will stop indexing users' uploaded files, and certainly slow down the indexing job as we will be loading ancestors.</p>
<p><span>It's important to note that despite this adjustment, users' uploaded files will remain accessible to all editors through the Form Submissions View. Depending on the sensitivity of the uploaded user's data, it's imperative to consider this accessibility. Ideally, in cases where user data is sensitive, refrain from saving form submissions within forms due to the limited security associated with form submissions. </span></p>
<p><span>Editors play a pivotal role in designing forms, and their training is crucial, particularly in alignment with the nature of the business, the type of information they will be gathering, and the relevant legislation. Training should ensure that editors understand the intricacies of data collection, its implications, and compliance requirements. </span></p>Toptip - what is .well-known folder/blogs/K-Khan-/Dates/2024/1/toptip----well-known-folder/2024-01-15T12:46:00.0000000Z<p><span>Within your </span><code>~/public</code><span> folder, you may come across a directory named ".well-known." This directory is frequently employed in web-based protocols to retrieve "site-wide metadata" related to a host before initiating a request. It's important to note that the absence of this folder doesn't necessarily indicate an issue; it simply means it hasn't been utilized or generated yet.</span></p>
<p>Here are some examples of what you might find in the ".well-known" directory:</p>
<ol>
<li><strong>.well-known/security.txt:</strong> Contains information about a website's security policies and <a href="https://securitytxt.org/">contact information for security researchers</a>.<br />Please read some helpful blogs on this topic.<br /><a href="https://www.gulla.net/en/blog/security.txt">https://www.gulla.net/en/blog/security.txt</a><br /><a href="https://optimizely.blog/2023/03/easy-implementation-of-security.txt-with-minimal-api-.net-core">https://optimizely.blog/2023/03/easy-implementation-of-security.txt-with-minimal-api-.net-core</a></li>
<li>
<p><strong>.well-known/apple-app-site-association (AASA):</strong> Used for <a href="https://developer.apple.com/library/archive/documentation/General/Conceptual/AppSearch/UniversalLinks.html">associating iOS apps with websites</a>, enabling features like Universal Links. This file doesn't have an extension.</p>
</li>
<li><strong>.well-known/assetlinks.json: </strong><span>Used in the context of Android App Links. <a href="https://developer.android.com/training/app-links/verify-android-applinks">Android App Links</a> are a way to associate a website with a specific Android app, allowing the app to open when certain links are clicked, even if the app is not currently installed on the device.</span></li>
</ol>Top tip - Auto Suggestion for editors/blogs/K-Khan-/Dates/2023/12/top-tip---auto-suggestion-for-editors/2023-12-28T11:22:21.0000000Z<p><span>Auto-suggestion can significantly enhance the efficiency, consistency, and overall quality of content created and managed by editors in a content management system. It serves as a valuable tool that supports editors in maintaining high standards and streamlining their workflow. </span>This small feature can benefit editors in many ways such as saving time by predicting and suggesting words or phrases for some fields as they type. It can promote consistency in writing style and terminology across the content. Editors will adhere to specific style guides or content standards if required for some fields.</p>
<p><span>Developers can add simple built-in auto-suggestions for editors to select when working in the edit view of Optimizely Content Management System (CMS)</span></p>
<p><span>Create a Custom selection class by inheriting ISelectionQuery e.g.</span></p>
<pre class="language-csharp"><code>using System;
using System.Collections.Generic;
using System.Linq;
using EPiServer.ServiceLocation;
using EPiServer.Shell.ObjectEditing;
namespace EPiServer.Samples
{
[ServiceConfiguration(typeof(ISelectionQuery))]
public class MySelectionQuery : ISelectionQuery
{
SelectItem[] _items;
public MySelectionQuery()
{
_items = new SelectItem[] {
new SelectItem() { Text = String.Empty, Value = String.Empty },
new SelectItem() { Text = "Alternative1", Value = "1" },
new SelectItem() { Text = "Alternative 2", Value = "2" } };
}
//Will be called when the editor types something in the selection editor.
public IEnumerable<ISelectItem> GetItems(string query)
{
return _items.Where(i => i.Text.StartsWith(query, StringComparison.OrdinalIgnoreCase));
}
//Will be called when initializing an editor with an existing value to get the corresponding text representation.
public ISelectItem GetItemByValue(string value)
{
return _items.FirstOrDefault(i => i.Value.Equals(value));
}
}
}</code></pre>
<p>Add the <strong>AutoSuggestionEditor</strong> attribute with your properties as below and set the <strong>AllowCustomValues</strong> property to true so that the editor is not forced to select one of the suggested choices. By default, this property is set to false and the editor must select one of the suggested values.</p>
<pre class="language-csharp"><code>[AutoSuggestSelection(typeof(MySelectionQuery))]
public virtual string SelectionEditor1 { get; set; }
[AutoSuggestSelection(typeof(MySelectionQuery), AllowCustomValues = true)]
public virtual string SelectionEditor2 { get; set; }</code></pre>Top tip - Health Checks/blogs/K-Khan-/Dates/2023/12/top-tip---health-checks/2023-12-26T14:28:06.0000000Z<p>Whether your site is a DXP or an Azure-hosted site, you may need to determine the <span>state of your application as if it's healthy or unhealthy. EPiServer.Cms.HealthCheck will provide you an endpoint as /epi/health, The Blog (<a href="/link/e7fd6d67f00e484d94be75b644c597be.aspx">https://world.optimizely.com/blogs/scott-reed/dates/2023/3/optimizely-dxp-health-checks-and-creating-custom-checks/</a>) by Scott Reed explains this setup for CMS 12 in detail. It doesn't limit us to service health only, Service can be extended for many other scenarios such as listing the vulnerabilities, and checking up on some configurations or DB table sizes. The blog is a bit old but still worth reading (<a href="https://www.codeart.dk/blog/2021/5/new-project-optimizely-episerver-health-checker/">https://www.codeart.dk/blog/2021/5/new-project-optimizely-episerver-health-checker/</a>).</span></p>
<p><span>"love what you do"</span></p>Monolith, JAMStack, SPA, or Composable, Optimizely CMS is the best fit/blogs/K-Khan-/Dates/2023/10/monolith-jamstack-spa-or-composable-optimizely-cms-is-a-best-fit/2023-10-14T17:44:53.0000000Z<p>Each website architecture has its own benefits and challenges.</p>
<p>Monolith is a traditional and proven architecture to deliver web apps, combining FE and BE.</p>
<p>To craft a JAMStack site, you employ static-site generation tools such as NextJS or Gatsby. These tools transform your website into HTML during the building process, thus introducing a game-changing shift as pages are constructed at a separate juncture.</p>
<p>JAMStack is often confused with SPA, but there are a few fundamental differences. A Single Page Application (SPA) is constructed directly within a user's browser. When a visitor requests a page, the markup and JavaScript are transmitted to the user's browser, and the webpage is dynamically assembled in real time.</p>
<p>Composable architecture focuses on Infrastructure as code, infrastructure automation, multi-cloud strategy, and portfolio rationalization.</p>
<p>Optimizely does not drive the architecture anymore but gives the flexibility to adopt any architecture that suits best to business for all of your content requirements.</p>
<p><img src="https://i.ibb.co/Sy4p6fB/architecture.jpg" width="661" alt="Options" height="263" style="display: block; margin-left: auto; margin-right: auto;" /></p>
<ul>
<li>SAS Core was introduced on Opticon San Deigo 2023 along with many other exciting enhancements and will be available in early 2024, PAS Core is the CMS that we know to date, We can get content from any source other than the CMS also</li>
<li><span>Optimizely Graph (Semantic and flexible search) converts your content into a graph structure. Just as search engines crawl the web to construct graph-based content indices, Optimizely Graph reshapes your CMS content for easy querying. It allows you to explore and manipulate your content using the GraphQL standard</span></li>
<li><span>Builder is a visual editor</span></li>
<li><span>Single source for all of your content needs, consume content anywhere</span></li>
<li><span>Content will remain available, even if CMS goes down</span></li>
<li><span>PAS/Head solution will be available with or without the Optimizely graph</span></li>
</ul>Considerations before you decide to use Content Definition API/blogs/K-Khan-/Dates/2022/12/considerations-before-you-decide-to-use-content-definition-api/2022-12-30T14:06:19.0000000Z<p>With the introduction of Content Definition API, it became possible to keep the definitions of the content structures, entirely in Front End and design a true headless solution with complete separation of the back end and front end. We can manage types via API and create new types as blocks and pages even without a release of the backend and create strongly typed typescript objects depending on the solution. Before you decide whether the use of Content Definition API is the right solution for you or not, you will need to consider the following points.</p>
<ul>
<li>Example projects such as <a href="https://github.com/episerver/content-delivery-js-sdk">https://github.com/episerver/content-delivery-js-sdk</a> rely on a single big manifest.json to define all the types. To achieve strongly typed objects, you will still need extra development efforts, there could be different approaches to achieve this, e.g. <a href="https://github.com/episerver/Foundation-spa-react/tree/Cms12/">https://github.com/episerver/Foundation-spa-react/tree/Cms12/</a></li>
<li>If you are writing a solution for DXP and considering Content Definition API just for the sake of achieving strongly typed objects, then an alternative approach could be to use Content Graph <a href="/link/2aefcdfa9169413db278877740df254a.aspx">https://world.optimizely.com/blogs/Jonas-Bergqvist/Dates/2022/9/strongly-typed-cms-content-with-typescript--react3/</a></li>
<li>Types generated via Content Definition API are of Types from DB, the feature available for CMS Editor for Types from code will not be available.</li>
<li>There is no replacement available for some .Net attributes such as AllowedTypes (e.g. to restrict ContentArea for specific blocks)</li>
<li>All settings available in the admin UI are not available through the API yet. For example, you cannot manage websites, languages, or translations.</li>
<li>Since changes could be made to the same content types but from different sources, there may be conflicts that could affect existing content. To reduce the risk of conflicts, you should add version information to the content types. To deal with the conflicts, follow semantic versioning <a href="https://docs.developers.optimizely.com/content-cloud/v1.7.0-content-definitions-api/docs/semantic-versioning">https://docs.developers.optimizely.com/content-cloud/v1.7.0-content-definitions-api/docs/semantic-versioning</a></li>
<li>The Language Branch API is available only in version 3.4.0 or later of the Content Definitions API.</li>
</ul>academy.episerver.com - SAP Litmos error/blogs/K-Khan-/Dates/2021/8/academy-episerver-com---sap-litmos/2021-08-16T07:42:24.0000000Z<p>'academy.episerver.com' URL wasn't working for me, rather showing some confusing message about SAP Litmos... don't wait that site will come back sooner. Just readjust bookmarks, as 'academy.optimizely.com' is the URL to use onwards. Same credentials should work.<br /><br /></p>ODP handy reference guide - Web SDK/blogs/K-Khan-/Dates/2021/6/odp-handy-reference-guide---web-sdk/2021-06-22T11:06:19.0000000Z<p>A quick reference guide, developers might need before starting a new ODP/Zaius implementation based on <a href="https://docs.developers.zaius.com/">https://docs.developers.zaius.com/</a></p>
<p>It will be worthy to watch <a href="https://www.david-tec.com/2021/05/video-adding-optimizely-data-platform-to-optimizely-commerce-cloud/">https://www.david-tec.com/2021/05/video-adding-optimizely-data-platform-to-optimizely-commerce-cloud/</a></p>
<div class="mce-toc">
<ul>
<li><a href="#mcetoc_1f8pln9370">Authentication</a></li>
<li><a href="#mcetoc_1f8pln9381">Batch Requests</a></li>
<li><a href="#mcetoc_1f8pln9382">Consent</a></li>
<li><a href="#mcetoc_1f8pln9383">Messaging Lists</a></li>
<li><a href="#mcetoc_1f8pln9384">Customers/Profiles</a></li>
<li><a href="#mcetoc_1f8pln9385">Custom event:</a></li>
<li><a href="#mcetoc_1f8pln9386">Standard events:</a></li>
</ul>
</div>
<h2>Authentication</h2>
<p>ODP/Zaius provides two forms of authentication:</p>
<ul>
<li>Public (Tracker ID) - is used for most API calls that send data</li>
<li>Private - is used for querying data</li>
</ul>
<p>Keys are scoped at the account level. When you revoke a private API key, your existing key is available for 12 hours as a grace period. Public API Key and Tracker ID are synonymous.</p>
<h2>Batch Requests</h2>
<p>Bulk data push should be done in batch, every request can include up to 500 distinct objects. As an example, at 500 customers per request with 10 requests per second as a rate limit, you can process 5,000 customer updates per second. For higher rate limits contact support.</p>
<h2>Consent</h2>
<p>Consent may impact attempts to send marketing campaigns to the identifier. If noted as opted-out, certain marketing services or channels may skip the identifier, even when qualified for the campaign. Customers who have opted out cannot receive marketing messages. Only transactional messages will be received by these customers.</p>
<p>Example: </p>
<pre class="language-javascript"><code>zaius.consent({ consent: true, identifier_field_name: 'email', identifier_value: 'tyler@zaius.com', update_reason: '', update_ts: 123456789, event_data: {} });</code></pre>
<h2>Messaging Lists</h2>
<p>Group customers for the purposes of tracking their communication preferences.</p>
<h2>Customers/Profiles</h2>
<p>To Create/Update/View Customer’s profile. Cookie with name ‘vuid’ contains the reference to profile id.<a href="https://docs.developers.zaius.com/api/rest-api/customers"></a></p>
<p>Anonymize - will reset the cookie identifier associated with the browser. Use this when a user logs out or on shared devices between form submissions that include identifiers.</p>
<p>Example:</p>
<pre class="language-javascript"><code>zaius.customer({
email: "johnny.zaius@zaius.com"
},{
first_name: "Johnny",
last_name: "Zaius",
gender: "M"
});</code></pre>
<p>Events</p>
<p>Customer behaviors are tracked as events. <span>Events are composed of a Type(a categorical name associated with the event), Action(activity a user did within that event type), and additional metadata via fields on the event, </span> <span>at minimum, events require an event type and an identifier to associate the event with a customer. </span>There are two types of events, custom, and standard,</p>
<h2>Custom event:</h2>
<p>Example:</p>
<pre class="language-javascript"><code>zaius.event("your_event_type_here", {
action: "your_event_action_here",
example_custom_field: "example_value"
});</code></pre>
<h2>Standard events:</h2>
<p><span class="text-4505230f--TextH400-3033861f--textContentFamily-49a318e1"><span>These are pre-defined event type/action and expected by Zaius to be accompanied with certain fields. The usage of these events makes the usage of Zaius simpler for common use cases. Zaius does not recommend or formally support Order events via the Web SDK to ensure that ad blockers do not block the purchase event. Zaius only supports sending Order refunds, returns & cancellations via API or CSV to ensure that ad blockers do not block these critical events. <a href="https://docs.developers.zaius.com/api/">https://docs.developers.zaius.com/api/</a></span></span></p>
<table>
<tbody>
<tr>
<td>Event TYPE</td>
<td>Activity</td>
<td>Example</td>
</tr>
<tr>
<td>https://docs.developers.zaius.com/web-sdk/events/account</td>
<td></td>
<td></td>
</tr>
<tr>
<td><strong>account</strong></td>
<td><strong>login</strong></td>
<td>
<pre class="language-javascript"><code>zaius.event("account", { action: "login" });</code></pre>
</td>
</tr>
<tr>
<td></td>
<td><strong>logout</strong></td>
<td>
<pre class="language-javascript"><code>zaius.event("account", { action: "logout" });</code></pre>
</td>
</tr>
<tr>
<td></td>
<td><strong>register</strong></td>
<td>
<pre class="language-javascript"><code>zaius.event("account", { action: "register" });</code></pre>
</td>
</tr>
<tr>
<td></td>
<td><strong>update</strong></td>
<td>
<pre class="language-javascript"><code>zaius.event("account", { action: "update" });</code></pre>
</td>
</tr>
<tr>
<td><span>Anonymize will reset the cookie identifier associated with the browser. Use this when a user logs out or on shared devices between form submissions that include identifiers.</span></td>
<td></td>
<td></td>
</tr>
<tr>
<td><strong>anonymise</strong></td>
<td></td>
<td>
<pre class="language-javascript"><code>zaius.anonymize();
</code></pre>
</td>
</tr>
<tr>
<td><span>Zaius will automatically parse the appropriate page path information.</span></td>
<td></td>
<td></td>
</tr>
<tr>
<td><strong>pageview</strong></td>
<td></td>
<td>
<pre class="language-javascript"><code>zaius.event("pageview");</code></pre>
</td>
</tr>
<tr>
<td>https://docs.developers.zaius.com/web-sdk/events/navigation</td>
<td></td>
<td></td>
</tr>
<tr>
<td><strong>navigation</strong></td>
<td><strong>search</strong></td>
<td>
<pre class="language-javascript"><code>zaius.event("navigation", {
action: "search",
search_term:"cameras, vcr",
category: "electronics > consumer"
});</code></pre>
</td>
</tr>
<tr>
<td></td>
<td><strong>sort</strong></td>
<td>
<pre class="language-javascript"><code>zaius.event("navigation", {
action: "sort"
});</code></pre>
</td>
</tr>
<tr>
<td></td>
<td><strong>filter</strong></td>
<td>
<pre class="language-javascript"><code>zaius.event("navigation", {
action: "filter"
});</code></pre>
</td>
</tr>
<tr>
<td>https://docs.developers.zaius.com/web-sdk/customers/consent</td>
<td></td>
<td></td>
</tr>
<tr>
<td><strong>consent</strong></td>
<td><strong>opt-in</strong></td>
<td>
<pre class="language-javascript"><code>zaius.consent({
consent: true,
identifier_field_name: 'email',
identifier_value: 'tyler@zaius.com',
update_reason: '',
update_ts: 123456789,
event_data: {}
});</code></pre>
</td>
</tr>
<tr>
<td></td>
<td><strong>opt-out</strong></td>
<td></td>
</tr>
<tr>
<td>
<p><a href="https://docs.developers.zaius.com/web-sdk/events/products">https://docs.developers.zaius.com/web-sdk/events/products</a></p>
<p>product_id is required on all events with an event type of product</p>
</td>
<td></td>
<td></td>
</tr>
<tr>
<td><strong>product</strong></td>
<td><strong>detail</strong></td>
<td>
<pre class="language-javascript"><code>zaius.event("product", { action: "detail", product_id: "product-2143" });</code></pre>
</td>
</tr>
<tr>
<td></td>
<td><strong>add_to_cart</strong></td>
<td>
<pre class="language-javascript"><code>zaius.event("product", { action: "add_to_cart", product_id: "product-2143" });</code></pre>
</td>
</tr>
<tr>
<td></td>
<td><strong>remove_from_cart</strong></td>
<td>
<pre class="language-javascript"><code>zaius.event("product", { action: "remove_from_cart", product_id: "product-2143" });</code></pre>
</td>
</tr>
<tr>
<td></td>
<td><strong>add_to_wishlist</strong></td>
<td>
<pre class="language-javascript"><code>zaius.event("product", { action: "add_to_wishlist", product_id: "product-2143" });</code></pre>
</td>
</tr>
<tr>
<td></td>
<td><strong>remove_from_wishlist</strong></td>
<td>
<pre class="language-javascript"><code>zaius.event("product", { action: "remove_from_wishlist", product_id: "product-2143" });</code></pre>
</td>
</tr>
<tr>
<td>https://docs.developers.zaius.com/web-sdk/events/ads</td>
<td></td>
<td></td>
</tr>
<tr>
<td><strong>advertisement</strong></td>
<td><strong>impression</strong></td>
<td>
<pre class="language-javascript"><code>zaius.event("advertisement", { action: "impression" });</code></pre>
</td>
</tr>
<tr>
<td></td>
<td><strong>click</strong></td>
<td>
<pre class="language-javascript"><code>zaius.event("advertisement", { action: "click" });</code></pre>
</td>
</tr>
<tr>
<td>
<p><span class="text-4505230f--TextH400-3033861f--textContentFamily-49a318e1"><span>Messaging Lists allow you to group customers for the purposes of tracking their communication preferences. For example, allowing customers to subscribe to your company newsletter or for holiday news. </span></span></p>
<div class="reset-3c756112--blockHint-a7403a60">
<p><span class="text-4505230f--TextH400-3033861f--textContentFamily-49a318e1"><span>Zaius does not require customers to be subscribed to a List to receive emails.</span></span></p>
</div>
</td>
</tr>
<tr>
<td>subscribe</td>
<td></td>
<td>
<pre class="language-javascript"><code>// subscribe johnny@zaius.com to newsletter list
zaius.subscribe({list_id: 'newsletter', email: 'johnny@zaius.com'});
// unsubscribe johnny@zaius.com from newsletter list
zaius.unsubscribe({list_id: 'newsletter', email: 'johnny@zaius.com'});
// subscribe johnny@zaius.com to three lists at once
zaius.subscribe({
list_id: ["newsletter", "promotion", "product_update"],
email: "johnny@zaius.com"
});
// unsubscribe johnny@zaius.com from multiple lists at once
zaius.unsubscribe({
list_id: ["newsletter", "product_update"],
email: "johnny@zaius.com"
});
zaius.subscribe({
// subscribe Johnny to all lists
list_id: ["newsletter", "promotion", "product_update"],
email: "johnny@zaius.com",
// update Johnny's record to include his full name
first_name: "Johnny",
last_name: "Zaius",
// store information on the subscribe events
event_custom_field: "my custom value",
custom_number_field: 123
});
// zaius.unsubscribe also fully supports this syntax.</code></pre>
</td>
</tr>
</tbody>
</table>Zaius was destined to Optimizelyhttps://digitalpixie.co.uk/?p=2042021-05-28T11:27:39.0000000ZOptimizely(EPiServer)’s CDP journey that started from EPiServer Profile Store, destined to Optimizely Data Platform(Zaius). With the acquisition of Zaius, Optimizely (EPiServer) have a true and one of most sophisticated CDP into their product family. Partners and customers already having licenses of Visitor Intelligence should contact EPiServer/Optimizely support to know more about migrations plans. Visitor Intelligence […]Security Mattershttp://digitalpixie.co.uk/?p=1252021-01-21T17:33:02.0000000ZNo matter what is the size of your website, your project is handling sensitive information or it’s just a feedback form, Cyber Security matters for all. You are a novice or an expert, a developer, QA, or a solution architect, in your team. A team should have basic knowledge of cyber security. In the project […]Episerver in microservices paradigm/blogs/K-Khan-/Dates/2020/6/episerver-in-microservices-paradigm/2020-06-02T13:42:12.0000000Z<p>“A microservices architecture is an approach to build a server application as a set of small services. That means a microservices architecture is mainly oriented to the back-end, although the approach is also being used for the front end. Each service runs in its own process and communicates with other processes using protocols such as HTTP/HTTPS, WebSockets, or AMQP. Each microservice implements a specific end-to-end domain or business capability within a certain context boundary, and each must be developed autonomously and be deployable independently. Finally, each microservice should own its related domain data model and domain logic and could be based on different data storage technologies (SQL, NoSQL) and different programming languages.”[1]</p>
<p>In Microservices architecture generally, contents are also served as a service, aka CaaS. The term CaaS refers to focus on managing structured contents that some restful/web services or feed that other subscribers or applications could consume. CaaS can be referred to as an abstraction on top of a headless CMS delivered via SaaS. A headless CMS is considered a good candidate to use in a microservices architecture. Generally developing a microservice is simple but overall architecture is complex. Planning a strong architecture is a key in microservices-based architectures. Selecting the right CMS is also one of the complex questions if a business is looking for some advanced CMS with features like personalization, analytics, and AI.</p>
<h1>Is EPiServer Headless CMS a fit in the microservice landscape?</h1>
<p><img src="https://i.ibb.co/MhZ6MPs/Microservices.jpg" alt="" /></p>
<ul>
<li>In EPiServer Headless, contents are served as JSON via a restful API so any programming language can consume.</li>
<li>Provide content for native applications that are not HTML-based and Independence to integrate any new channel as we are not bounded with the CMS functionalities.</li>
<li>It is Pluggable and configurable web API</li>
<li>Support localized content and multi-site scenarios.</li>
<li>Support common querying, filtering, and sorting scenarios, able to query contents through Content Search API providing robust filtering and sorting via OData syntax</li>
<li>Support returning access-controlled and personalized content where required.</li>
<li>Scaleable and secure, Docker could be an option but might not be the best option to set up EpiServer Headless CMS. "<span>Episerver chose </span><a href="https://azure.microsoft.com/en-us/">Microsoft Azure</a><span> to support its Customer-Centric Digital Experience Platform, using </span><a href="https://azure.microsoft.com/en-us/services/kubernetes-service/">Azure Kubernetes Service (AKS)</a><span> as the orchestration engine for high-availability multitenant microservices and </span><a href="https://azure.microsoft.com/en-us/services/app-service/">Azure App Service</a><span> for easily scalable web app deployment". </span>By default supports OAuth and cookie-based authentication, However, it is allowed to customize the authorization flow and use your preferred authorization mechanism like AzureAD or GitHub.</li>
<li>Framework agnostic features such as on Page Editing can be used with any javascript framework such as Angular, React, or Vue.</li>
</ul>
<h2>EPiServer Headless</h2>
<p><a href="/link/6ffa5cb8173a414eac25740deeafdbc8.aspx">https://world.episerver.com/documentation/developer-guides/content-delivery-api/</a></p>
<p><img src="/link/7ce146c1219c46cfb41062d597a23723.aspx" alt="" /></p>
<h2>Future Of EPiServer Headless</h2>
<p><a href="/link/be8077bc415c4afca844daf0fb0e83bb.aspx">https://world.episerver.com/blogs/martin-ottosen/dates/2019/12/asp-net-core-beta-program/</a></p>
<p><img src="/link/e64362f8872e492ab4f3191267c0c760.aspx" alt="" /></p>
<h1>Contextual considerations</h1>
<p>Conceptually a microservice can be derived as a bounded context in a domain-driven design where each bounded context should have its own model and database. EPiServer CMS as a whole should be considered as a single bounded context. Content in itself can’t be divided further into microservices-based into their types (Images, Textual, or Pdfs).</p>
<p> </p>
<h1>Content Considerations</h1>
<p>In EPiServer a content item is not necessarily only a web page, it may not have an addressable URL and it may be just a container for data that can be seen as a database record. Sometimes, the same piece of content can be used on a page, on social media or in print which means the content is no longer assigned to a specific channel. Usually, those kinds of content items are simple with only basic property types and some metadata. Content Manager is available to create this kind of content.</p>
<p><a href="/link/dbbcb8c637ae4dcc80685dd99ca3ae05.aspx">https://world.episerver.com/blogs/bartosz-sekula/dates/2020/4/content-manager---lightweight-editing-ui/</a></p>
<p><img src="/link/a4d4968ba9234975b52bfe6fe9719702.aspx" alt="" /></p>
<p><img src="/link/d9d8c3d5dc6249f88ad78c93cc70840c.aspx" alt="" /></p>
<h1>SPA implementations with Headless CMS with OPE support</h1>
<p><a href="/link/77c693a1814446ffb2f76af6babbef08.aspx">https://world.episerver.com/blogs/remko-jantzen/dates/2020/5/introducing-foundation-spa-react/</a></p>
<p><a href="https://github.com/episerver/musicfestival-vue-template">https://github.com/episerver/musicfestival-vue-template</a></p>
<p><strong>References</strong></p>
<p>[1] - <a href="https://docs.microsoft.com/en-us/dotnet/architecture/microservices/">https://docs.microsoft.com/en-us/dotnet/architecture/microservices/</a></p>
<p><a href="/link/dbbcb8c637ae4dcc80685dd99ca3ae05.aspx">https://world.episerver.com/blogs/bartosz-sekula/dates/2020/4/content-manager---lightweight-editing-ui/</a></p>
<p><a href="https://customers.microsoft.com/en-gb/story/786162-episerver-partner-professional-services-azure">https://customers.microsoft.com/en-gb/story/786162-episerver-partner-professional-services-azure</a></p>How your site appears in google search resultshttp://kkhan-episerver.blogspot.com/2020/05/how-your-site-appears-in-google-search.html2020-05-06T10:06:00.0000000ZSearch engines now look deep into site contents and try to understand more about your site e.g. Google uses structure data to understand more about the content on your page. By providing structured data we not only can get the benefit of special features like rich snippets but also our site will be eligible to appear in graphic search results. By providing structured data you can outstand your site presence in the google search results and in result increase in clickthrough.<br /><br />While searching keyword 'eCommerce' (from the UK, 5th of May 2020) I get the following results.<br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-tKZ7bjdxOv4/XrGWZO9XoqI/AAAAAAAAROg/6e5tDbHHUPQyhFy_E4ZXEqW0SXxmHPwHgCLcBGAsYHQ/s1600/ecommerce.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="859" data-original-width="1345" height="408" src="https://1.bp.blogspot.com/-tKZ7bjdxOv4/XrGWZO9XoqI/AAAAAAAAROg/6e5tDbHHUPQyhFy_E4ZXEqW0SXxmHPwHgCLcBGAsYHQ/s640/ecommerce.JPG" width="640" /></a></div><br />These are the highlights of the page<br /><br /><ol><li><a href="https://support.google.com/websearch/answer/9351707?p=featured_snippets">Featured snippet</a></li><li>Related Images</li><li>Article</li><li>Books</li><li>People also searched for</li><li>FAQ<br />and the rest of the search results.</li></ol><div>Google supports structured data in the following formats <a href="http://json-ld.org/">JSON-LD</a> (recommended, use this format whenever possible), <a href="https://www.w3.org/TR/microdata/">Microdata</a>, and <a href="https://rdfa.info/">RDFa</a>. Google also uses <a href="https://schema.org/">schema.org</a> vocabulary, but for definitive, google search behaviors, rely on documentation provided on developers.google.com rather schema.org.</div><div><br /></div><div>There can be several items in your site for which structure data can be provided, e.g. article, breadcrumb, carousel, event, FAQ, logo, organization, or product. You can find examples of JSON-LD structured data code snippets from google <a href="https://developers.google.com/search/docs/data-types/article">here</a>. A full list of vocabulary definition files can be downloaded from <a href="https://schema.org/docs/developers.html">schama.org</a>. </div><div><br /></div><div>Implementation of structured data could be very simple to complex depending on your site and the way pages and blocks are structured in the EPiServer site, general structure data guidelines are available <a href="https://developers.google.com/search/docs/guides/sd-policies">here</a>. A reference implementation based on the <a href="https://www.nuget.org/packages/Schema.NET/3.5.0">schema.net</a> package can be found in <a href="https://github.com/episerver/Foundation/tree/develop/src/Foundation.Cms/SchemaMarkup">EPiServer foundation project</a>. (Credits: Paul Gruffydd)</div><div><br /></div><div><br /></div><div><br /></div>How your site appears in google search resultshttps://digitalpixie.co.uk/how-your-site-appears-in-google-search-results2020-05-06T10:06:00.0000000ZSearch engines now look deep into site contents and try to understand more about your site e.g. Google uses structure data to understand more about the content on your page. By providing structured data we not only can get the benefit of special features like rich snippets but also our site will be eligible to […]Will your site be effected in Chrome 80/blogs/K-Khan-/Dates/2020/2/will-your-site-be-effected-with-chrome-80/2020-02-03T19:56:24.0000000Z<p>Chrome 80 will treat cookies as SameSite=Lax by default if no SameSite attribute is specified and will reject insecure SameSite=None cookies.</p>
<ul>
<li><a href="https://www.chromestatus.com/feature/5088147346030592">https://www.chromestatus.com/feature/5088147346030592</a></li>
<li><a href="https://www.chromestatus.com/feature/5633521622188032">https://www.chromestatus.com/feature/5633521622188032</a></li>
</ul>
<p>Out of the box EPi Server's CMS website functionality isn't effected, but it might be effecting other areas of your website. e.g.</p>
<p>your integrations with Identity Providers using protocols such as SAML 2.0 or OpenID Connect or analytics cookies that your web application creating as a third-party cookie or any feature depending on third party dependent cookies or if you are querying APIs from a third-party domain. </p>
<p>References:</p>
<ul>
<li><a href="https://www.chromestatus.com/features/schedule">https://www.chromestatus.com/features/schedule</a></li>
<li><a href="/link/a182c387633d45cda9e39c6a1aafc035.aspx">https://world.episerver.com/forum/developer-forum/-Episerver-75-CMS/Thread-Container/2020/1/upcoming-samesite-cookie-changes-and-episerver/</a></li>
<li><a href="https://auth0.com/blog/browser-behavior-changes-what-developers-need-to-know/">https://auth0.com/blog/browser-behavior-changes-what-developers-need-to-know/</a></li>
<li><a href="https://devblogs.microsoft.com/aspnet/upcoming-samesite-cookie-changes-in-asp-net-and-asp-net-core/">https://devblogs.microsoft.com/aspnet/upcoming-samesite-cookie-changes-in-asp-net-and-asp-net-core/</a></li>
<li><a href="https://www.chromium.org/updates/same-site">https://www.chromium.org/updates/same-site</a></li>
<li><a href="https://www.seerinteractive.com/blog/samesite-security-update-chrome/">https://www.seerinteractive.com/blog/samesite-security-update-chrome/</a></li>
<li><a href="https://webkit.org/blog/8828/intelligent-tracking-prevention-2-2/">https://webkit.org/blog/8828/intelligent-tracking-prevention-2-2/</a></li>
</ul>
<p>Google announced it would end support for third-party cookies in Chrome by 2022</p>
<ul>
<li><a href="https://blog.chromium.org/2020/01/building-more-private-web-path-towards.html">https://blog.chromium.org/2020/01/building-more-private-web-path-towards.html</a></li>
<li><a href="https://marketingland.com/marketers-respond-to-google-chrome-cookie-decision-with-mixture-of-hope-and-fear-274792">https://marketingland.com/marketers-respond-to-google-chrome-cookie-decision-with-mixture-of-hope-and-fear-274792</a></li>
</ul>
Use of strategy pattern to change page behaviour/blogs/K-Khan-/Dates/2020/1/use-of-strategy-pattern-to-change-page-behaviour/2020-01-01T16:32:05.0000000Z<p>There are scenarios where we have to change our page behavior or algorithms at run time based on Epi Configurations. Generally, a developer approaches with if-else statements to deal with this by compromising design principals. We can get help from the Strategy Pattern to adhere to SOLID principals. Below is an Illustrations for a fake scenario to demonstrate implementation where editors will set a recipe filter to change the results of the page or selecting the right dataset for the page.</p>
<p><img src="https://i.ibb.co/kJKJCCZ/strategy.jpg" alt="" /></p>
<p>EPiServer Page and configurations</p>
<pre class="language-csharp"><code>public enum LayoutType
{
Diabitic,
HighProtein,
LowFat,
HighFibre
}
/// <summary>
/// Create an interface for configuration
/// </summary>
public interface IStrategyConfiguration
{
LayoutType LayoutType { get; set; }
}
/// <summary>
/// Implement Configuration in your page or block
/// </summary>
public class RecipeLandingPage : PageData, IStrategyConfiguration
{
[Display(GroupName = SystemTabNames.Settings, Name = "Layout", Description = "Select page layout")]
public LayoutType LayoutType { get; set; }
}</code></pre>
<p>PageController/factory where we need to change the algorithm at runtime.</p>
<pre class="language-csharp"><code>/// <summary>
/// Page Controller
/// </summary>
public class RecipeLandingPageController : PageController<RecipeLandingPage>
{
/// <summary>
/// IRecipeFilterSelector is a resolver that will select right IRecipeFilter for us
/// </summary>
private readonly IRecipeFilterSelector _recipeFilterSelector;
public RecipeLandingPageController(IRecipeFilterSelector recipeFilterSelector)
{
_recipeFilterSelector = recipeFilterSelector;
}
public async Task<ActionResult> Index(RecipeLandingPage currentPage)
{
//Select a filter based on epi configurations
var filter = _recipeFilterSelector.GetRecipeFilter(currentPage.LayoutType);
var pageModel = YourPageModel(currentPage);
pageModel.Advertisements = filter.GetAdvertisements();
pageModel.Suggestions = filter.GetSuggestions();
return View(model);
}
}</code></pre>
<p>We need IRecipeFilterSelector that could return us correct IRecipeFilter.</p>
<pre class="language-csharp"><code> /// <summary>
/// will resolve correct IRecipeFilter
/// </summary>
public interface IRecipeFilterSelector
{
IRecipeFilter GetRecipeFilter(LayoutType layoutType);
}
/// <summary>
/// Select IRecipeFilter based on EPiCongigurations
/// </summary>
public class RecipeFilterSelector : IRecipeFilterSelector
{
private readonly IEnumerable<IRecipeFilter> _recipeFilters;
// structuremap will push all implementations of IRecipeFilter
public RecipeFilterSelector(IEnumerable<IRecipeFilter> recipeFilters)
{
_recipeFilters = recipeFilters;
}
public IRecipeFilter GetRecipeFilter(LayoutType layoutType)
{
return _recipeFilters.FirstOrDefault(x => x.LayoutType == layoutType);
}
}
</code></pre>
<p>We need separate implementations for IRecipeFilter</p>
<pre class="language-markup"><code>/// <summary>
/// Main service
/// </summary>
public interface IRecipeFilter
{
LayoutType LayoutType { get; }
IList<Advertisement> GetAdvertisements();
IList<Suggestion> GetSuggestions();
}
/// <summary>
/// Separation of concerns achieved, implementation for specific scenarios
/// </summary>
public class DiabiticRecipeFilter : IRecipeFilter
{
public LayoutType LayoutType => LayoutType.Diabitic;
public IList<Advertisement> GetAdvertisements()
{
throw new NotImplementedException();
}
public IList<Suggestion> GetSuggestions()
{
throw new NotImplementedException();
}
}
/// <summary>
/// Separation of concerns achieved, implementation for specific scenarios
/// </summary>
public class HighProteinRecipeFilter : IRecipeFilter
{
public LayoutType LayoutType => LayoutType.HighProtein;
public IList<Advertisement> GetAdvertisements()
{
throw new NotImplementedException();
}
public IList<Suggestion> GetSuggestions()
{
throw new NotImplementedException();
}
}
</code></pre>
<p>Join these pieces in structuremap to work together</p>
<pre class="language-csharp"><code>//Collect all implementations of IRecipeFilter
c.Scan(s =>
{
s.AssemblyContainingType(typeof(IRecipeFilter));
s.AddAllTypesOf(typeof(IRecipeFilter));
});
//pass this to selector
c.For<IRecipeFilterSelector>().Use<RecipeFilterSelector>().Singleton();</code></pre>
<p><img src="https://i.ibb.co/wp1nYbs/final.jpg" alt="" /></p>
<p>Be SOLID in the new year! Happy new year!</p>EPiServer FileUpload element - Allowed extensions check isn't enough/blogs/K-Khan-/Dates/2019/9/episerver-fileupload-element-allowed-file-types-only/2019-09-26T15:09:49.0000000Z<p>EPiServer Forms FileUpload element provides a property with the name '<span>Allowed extensions</span>', that enables content editors to allow website users to upload files in the required format. This can be spoofed easily e.g with value PDF only for allowed extension I am allowed to upload pdf files along with Funny-jpg.pdf also (I hope you got what I meant ;) ). It's a High-security risk for the sites that accept files from end-users via EPiServer forms. I have to come up with an immediate solution, hope this will help someone else also.</p>
<p>1 - extend FileUploadElementBlock (I was Lucky as already had an extended element in our code)</p>
<pre class="language-csharp"><code>public class StyledFileUploadElementBlock : FileUploadElementBlock
{
public override string Validators
{
get
{
var customValidator = typeof(FileContentTypeCustomValidator).FullName;
var validators = this.GetPropertyValue(content => content.Validators);
if (string.IsNullOrEmpty(validators))
{
return customValidator;
}
else
{
return string.Concat(validators, EPiServer.Forms.Constants.RecordSeparator, customValidator);
}
}
set
{
this.SetPropertyValue(content => content.Validators, value);
}
}
}</code></pre>
<p>2 - Write a service that could look into file signatures and could determine File Type based on the File Contents, not just extension. </p>
<p><a href="https://gist.github.com/khurramkhang/8e13cd4c1c9d9a947529036ede377fb6">Get file type by signatures</a></p>
<p>3 - Add your business logic for your custom validator</p>
<pre class="language-csharp"><code>public class FileContentTypeCustomValidator : ElementValidatorBase
{
private Injected<IFileValidationService> _fileService;
protected IFileValidationService FileValidationService { get { return _fileService.Service; } }
public override bool? Validate(IElementValidatable targetElement)
{
StyledFileUploadElementBlock fileUploadElementBlock = targetElement as StyledFileUploadElementBlock;
if (fileUploadElementBlock == null)
return true;
var files = targetElement?.GetSubmittedValue();
if (files == null)
return true;
var postedFiles = files as List<HttpPostedFile>;
if (postedFiles != null && postedFiles.Any())
{
foreach (var httpPostedFile in postedFiles)
{
//Your Business logic
var fileType = FileValidationService.GetFileType(httpPostedFile.InputStream);
if (string.IsNullOrEmpty(fileType.Extension))
return false;
if (!fileUploadElementBlock.FileExtensions.Contains(fileType.Extension))
{
return false;
}
}
}
return true;
}
public override bool AvailableInEditView
{
get
{
return false;
}
}
///
public override IValidationModel BuildValidationModel(IElementValidatable targetElement)
{
StyledFileUploadElementBlock fileUploadElementBlock = targetElement as StyledFileUploadElementBlock;
if (fileUploadElementBlock == null)
{
return base.BuildValidationModel(targetElement);
}
var fileExtensions = fileUploadElementBlock.FileExtensions;
if (base._model != null) return base._model;
string validatorMessage = base._validationService.Service.GetValidatorMessage(base.GetType(), (fileExtensions.Split(new string[1]
{
","
}, StringSplitOptions.RemoveEmptyEntries).Length != 0) ? "allowedextensionsmessage" : string.Empty);
base._model = new AllowedExtensionsValidationModel
{
Accept = fileExtensions,
Message = string.Format(validatorMessage, fileExtensions)
};
return base._model;
}
}</code></pre>
<p><br />Stay Safe!</p>
<p>EPiServer Forms version: 4.25.0</p>Best practises cheat sheet for your EPi site/blogs/K-Khan-/Dates/2019/6/prefer-over/2019-06-19T21:54:15.0000000Z<ul>
<li>Prefer Controllerless blocks</li>
<li>Don't Create Content Areas in Blocks, No nesting blocks.</li>
<li>Minimize database calls. Instead, use Episerver’s caching layer where ever possible.</li>
<li>Personalization might have an impact on performance, therefore make sure you implement personalization in a way that has the least possible impact.</li>
<li>Avoid frequent querying of the Dynamic Data Store.</li>
<li>Try to keep your content tree well balanced.</li>
<li>Prefer Lists over ContentArea where possible to avoid big content structures for complex pages.</li>
<li>Avoid dynamic properties.</li>
<li>Register UIDescriptor, where you disable on page edit and preview views</li>
<li>For settings kind of pages, ensure that it will not have a template</li>
<li>Use Episerver’s Object Cache instead of .NET’s built-in cache</li>
<li>Create all Content Types (Page Types, Block Types, Media Types) in code</li>
<li>For property (field) names in code, use standard .NET PascalCase. Make sure to set a friendly Display Name and Description</li>
<li>Plan a data hierarchy for Content Types, and use class inheritance</li>
<li>Organize groups of properties (fields) into tabs</li>
<li>Provide an order of properties, with frequently used properties at the top of each tab, Consider Editors</li>
<li>Set default values for Content Types’ Properties (if known)</li>
<li>For media properties, use the ContentReference type and the appropriate UIHint</li>
<li>Use the PropertyFor method to render properties (fields) in Content Type views</li>
<li>Make sure to always create the appropriate Media Types for assets in the project</li>
<li>Use Container Pages for folder nodes, without presentation (if required) use IContainerPage.</li>
<li>Plan carefully the content structure hierarchy, and avoid overloading a single level with too many pages</li>
<li>Make sure to load-test external systems integrations</li>
<li>Avoid resolving URLs repeatedly, think about cache.</li>
<li>Avoid creating blocks to use for image refernces and pages only along with some text as Alt</li>
</ul>
<p>Disclaimer: Points have been learned from many different sources and experience, have been adding in my best practices document.</p>Add Angular component in your EPiServer site/blogs/K-Khan-/Dates/2019/2/add-angular-component-in-your-episerver-site/2019-02-24T23:02:11.0000000Z<p><a href="https://angular.io/guide/architecture">Angular<span> </span></a><span>is a platform and framework for building client applications in HTML and TypeScript. Angular is written in TypeScript. It implements core and optional functionality as a set of TypeScript libraries that you import into your apps. It is easy to add Angular Components in our EpiServer MVC website with the following steps.</span></p>
<p><span>Follow this <a href="https://kkhan-episerver.blogspot.com/2019/02/add-angular-component-in-your-episerver.html">blog</a></span></p>EPiServer CMS 11 Useful SQL Queries - 2http://kkhan-episerver.blogspot.com/2019/02/episerver-cms-11-useful-sql-queries-2.html2019-02-14T14:40:00.0000000Z<span style="background-color: white; color: #323738; font-family: "simplon norm", arial, helvetica, sans-serif; font-size: 15px;">Here is a set of few queries that we have been using in different investigations</span><br /><span style="background-color: white; color: #323738; font-family: "simplon norm", arial, helvetica, sans-serif; font-size: 15px;"><br /></span><br /><ul><li><span style="background-color: white; color: #323738; font-family: "simplon norm", arial, helvetica, sans-serif; font-size: 15px;">Get usages of EPiServer contents including pages and blocks</span></li><li><span style="background-color: white; color: #323738; font-family: "simplon norm", arial, helvetica, sans-serif; font-size: 15px;">Check Table size</span></li><li><span style="background-color: white; color: #323738; font-family: "simplon norm", arial, helvetica, sans-serif; font-size: 15px;">No contents have been added for following content types</span></li><li><span style="color: #323738; font-family: "simplon norm", arial, helvetica, sans-serif; font-size: 15px;">Looking into Activity Logs</span></li><li><span style="color: #323738; font-family: "simplon norm", arial, helvetica, sans-serif; font-size: 15px;">Unmapped Property List</span></li></ul><br /><span style="color: #323738; font-family: "simplon norm", arial, helvetica, sans-serif; font-size: 15px;"><br /></span><span style="background-color: white; color: #323738; font-family: "simplon norm", arial, helvetica, sans-serif; font-size: 15px;"><b>Get usages of EPiServer contents including pages and blocks</b></span><br /><span style="color: #323738; font-family: "simplon norm", arial, helvetica, sans-serif; font-size: 15px;">SELECT</span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;"> tct.Name, </span></span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;"> tct.ModelType, </span></span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;"> COUNT(tc.pkID) AS PageCount</span></span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;">FROM</span></span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;"> tblContent AS tc RIGHT OUTER JOIN</span></span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;"> tblContentType AS tct ON tc.fkContentTypeID = tct.pkID</span></span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;">Where tct.ModelType is not null and tct.ModelType not like 'EPiServer.%'</span></span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;">GROUP BY</span></span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;"> tct.Name, tct.ModelType</span></span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;">ORDER BY</span></span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;"> PageCount desc</span></span><br /><br /><span style="background-color: white; color: #323738; font-family: "simplon norm", arial, helvetica, sans-serif; font-size: 15px;"><b>Check table size</b></span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;">EXEC sp_spaceused 'tblBigTable'</span></span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;"><br /></span></span><span style="background-color: white; color: #323738; font-family: "simplon norm", arial, helvetica, sans-serif; font-size: 15px;"><b>No contents have been added for following content types</b></span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;">SELECT</span></span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;"> tct.Name, </span></span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;"> tct.ModelType</span></span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;">FROM</span></span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;"> tblContent AS tc RIGHT OUTER JOIN</span></span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;"> tblContentType AS tct ON tc.fkContentTypeID = tct.pkID</span></span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;">Where tct.ModelType is not null and tct.ModelType not like 'EPiServer.%'</span></span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;">GROUP BY</span></span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;"> tct.Name, tct.ModelType</span></span><br /><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;">Having COUNT(tc.pkID) = 0</span></span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;"><br /></span></span><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;"><b>Looking into Activity Logs</b></span></span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;">exec netActvitiyLogList @from='2018-02-01', @to='2019-02-14', @maxRows=10</span></span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;"><br /></span></span><span style="color: #323738; font-family: "simplon norm", arial, helvetica, sans-serif; font-size: 15px;"><b>Unmapped Property List</b></span><br /><div><span style="color: #323738; font-family: "simplon norm", arial, helvetica, sans-serif; font-size: 15px;">SELECT tblContentProperty.LinkGuid AS GuidID, tblContentProperty.fkLanguageBranchID AS LanguageBranchID, tblPageDefinition.Name AS PropertyName, tblPageDefinition.fkPageTypeID AS PageTypeID, tblContentType.Name, </span></div><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;"> tblContentType.ModelType</span></span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;">FROM tblContentProperty INNER JOIN</span></span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;"> tblPageDefinition ON tblContentProperty.fkPropertyDefinitionID = tblPageDefinition.pkID INNER JOIN</span></span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;"> tblContent ON tblContentProperty.fkContentID = tblContent.pkID INNER JOIN</span></span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;"> tblContentType ON tblContent.fkContentTypeID = tblContentType.pkID</span></span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;">WHERE (tblContentProperty.LinkGuid IS NOT NULL) AND (tblContentProperty.ContentLink IS NULL)</span></span><br /><br /><br />EPiServer CMS 11 Useful SQL Queries - 2http://kkhan-episerver.blogspot.com/2019/02/episerver-cms-11-useful-sql-queries-2.html2019-02-14T13:40:00.0000000Z<span style="background-color: white; color: #323738; font-family: "simplon norm", arial, helvetica, sans-serif; font-size: 15px;">Here is a set of few queries that we have been using in different investigations</span><br /><span style="background-color: white; color: #323738; font-family: "simplon norm", arial, helvetica, sans-serif; font-size: 15px;"><br /></span><br /><ul><li><span style="background-color: white; color: #323738; font-family: "simplon norm", arial, helvetica, sans-serif; font-size: 15px;">Get usages of EPiServer contents including pages and blocks</span></li><li><span style="background-color: white; color: #323738; font-family: "simplon norm", arial, helvetica, sans-serif; font-size: 15px;">Check Table size</span></li><li><span style="background-color: white; color: #323738; font-family: "simplon norm", arial, helvetica, sans-serif; font-size: 15px;">No contents have been added for following content types</span></li><li><span style="color: #323738; font-family: "simplon norm", arial, helvetica, sans-serif; font-size: 15px;">Looking into Activity Logs</span></li><li><span style="color: #323738; font-family: "simplon norm", arial, helvetica, sans-serif; font-size: 15px;">Unmapped Property List</span></li></ul><br /><span style="color: #323738; font-family: "simplon norm", arial, helvetica, sans-serif; font-size: 15px;"><br /></span><span style="background-color: white; color: #323738; font-family: "simplon norm", arial, helvetica, sans-serif; font-size: 15px;"><b>Get usages of EPiServer contents including pages and blocks</b></span><br /><span style="color: #323738; font-family: "simplon norm", arial, helvetica, sans-serif; font-size: 15px;">SELECT</span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;"> tct.Name, </span></span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;"> tct.ModelType, </span></span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;"> COUNT(tc.pkID) AS PageCount</span></span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;">FROM</span></span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;"> tblContent AS tc RIGHT OUTER JOIN</span></span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;"> tblContentType AS tct ON tc.fkContentTypeID = tct.pkID</span></span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;">Where tct.ModelType is not null and tct.ModelType not like 'EPiServer.%'</span></span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;">GROUP BY</span></span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;"> tct.Name, tct.ModelType</span></span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;">ORDER BY</span></span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;"> PageCount desc</span></span><br /><br /><span style="background-color: white; color: #323738; font-family: "simplon norm", arial, helvetica, sans-serif; font-size: 15px;"><b>Check table size</b></span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;">EXEC sp_spaceused 'tblBigTable'</span></span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;"><br /></span></span><span style="background-color: white; color: #323738; font-family: "simplon norm", arial, helvetica, sans-serif; font-size: 15px;"><b>No contents have been added for following content types</b></span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;">SELECT</span></span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;"> tct.Name, </span></span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;"> tct.ModelType</span></span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;">FROM</span></span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;"> tblContent AS tc RIGHT OUTER JOIN</span></span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;"> tblContentType AS tct ON tc.fkContentTypeID = tct.pkID</span></span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;">Where tct.ModelType is not null and tct.ModelType not like 'EPiServer.%'</span></span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;">GROUP BY</span></span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;"> tct.Name, tct.ModelType</span></span><br /><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;">Having COUNT(tc.pkID) = 0</span></span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;"><br /></span></span><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;"><b>Looking into Activity Logs</b></span></span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;">exec netActvitiyLogList @from='2018-02-01', @to='2019-02-14', @maxRows=10</span></span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;"><br /></span></span><span style="color: #323738; font-family: "simplon norm", arial, helvetica, sans-serif; font-size: 15px;"><b>Unmapped Property List</b></span><br /><div><span style="color: #323738; font-family: "simplon norm", arial, helvetica, sans-serif; font-size: 15px;">SELECT tblContentProperty.LinkGuid AS GuidID, tblContentProperty.fkLanguageBranchID AS LanguageBranchID, tblPageDefinition.Name AS PropertyName, tblPageDefinition.fkPageTypeID AS PageTypeID, tblContentType.Name, </span></div><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;"> tblContentType.ModelType</span></span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;">FROM tblContentProperty INNER JOIN</span></span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;"> tblPageDefinition ON tblContentProperty.fkPropertyDefinitionID = tblPageDefinition.pkID INNER JOIN</span></span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;"> tblContent ON tblContentProperty.fkContentID = tblContent.pkID INNER JOIN</span></span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;"> tblContentType ON tblContent.fkContentTypeID = tblContentType.pkID</span></span><br /><span style="color: #323738; font-family: simplon norm, arial, helvetica, sans-serif;"><span style="font-size: 15px;">WHERE (tblContentProperty.LinkGuid IS NOT NULL) AND (tblContentProperty.ContentLink IS NULL)</span></span><br /><br /><br />