Using Display Name and Generating links for multilingual sites – Sitecore

About Display Name:

As many of us already aware, Display Name is used

In case of multilingual sites, where we required to generate links for pages specific to the language it is serving. For ex: there is a page in website named about-us and website is available in two languages English, and German. Now URL should be formed according to language as shown below:

This can be achieved by the feature referred as Display Name in Sitecore.

How to Assign Display Name

  • Create an item in Sitecore with the preferred name, in our example it is about-us.
  • For English language version display name will be same as item name so we will skip this part for English language.
  • For German language, Select the German language version of an item, click on Home (tab) -> Rename (chunk) -> Display Name command from the ribbon bar in content editor (You can also assign Display Name from Experience Editor).
  • A popup will appear expecting a text, enter the display name specific to the language which will then be used to form language specific URL. In our example equivalent to contact-us will be kontaktiere-uns, so enter this in textbox and save.
  • That’s it from the configuration part. You will see entered display name in content tree now instead of item name.

Generating Links While Using Display Name Feature

To generate URL specific to language using Display Name, You need to add useDisplayName=”true” into linkmanager in the sitecore.config. See below:


<linkManager defaultProvider="sitecore">
    <providers>
      <clear/>
      <add name="sitecore" type="Sitecore.Links.LinkProvider, Sitecore.Kernel" addAspxExtension="false" alwaysIncludeServerUrl="false" encodeNames="true" languageEmbedding="always" languageLocation="querystring" lowercaseUrls="true" shortenUrls="true" useDisplayName="true"/>
    </providers>
</linkManager>

After enabling Display Name in link manager, you can now generate link using link manager as follow:

Consider context language as English, and we need to generate link for German language version of item using display name. We can do it simply using link manager in view as:


@{

Sitecore.Links.UrlOptions options = new Sitecore.Links.UrlOptions();
options.Language = Sitecore.Data.Managers.LanguageManager.GetLanguage("de-DE");
options.LanguageEmbedding = Sitecore.Links.LanguageEmbedding.Always;
options.LanguageLocation = Sitecore.Links.LanguageLocation.QueryString;
options.UseDisplayName = true;

string URL = Sitecore.Links.LinkManager.GetItemUrl(Sitecore.Context.Item, options);

}

Will this generate the link we desire for German (de-DE) language? No.

The link generated using the above code will look something like http://[hostname]/about-us?sc_lang=de-DE

Why we are showing about-us in the URL instead of the kontaktiere-uns even though we have supplied language de-DE in UrlOptions.

After drilling down to Linkmanager code, come to know that language passed into UrlOptions not getting used while getting Display Name, It is getting Display Name of the item provided as first parameter of GetItemUrl()

In our case we are passing context item, and context language is English. As we do not have provided any Display Name for this item in English language, it will use Item Name itself to generate the URL.

So, we need to get the item in specific language before passing to GetItemUrl() function to form valid URL specific to language with help of Display Name. See below:


@{

string URL = Sitecore.Links.LinkManager.GetItemUrl(Sitecore.Context.Item, options);

}

In place of above line use below code:


@{

string URL = @Sitecore.Links.LinkManager.GetItemUrl(Sitecore.Context.Database.GetItem(Sitecore.Context.Item.ID, Sitecore.Data.Managers.LanguageManager.GetLanguage("de-DE")), options);

}

So, above code will first get German version of the about-us item, and thus will form a valid URL using Display Name provided for German language.

Unit Testing in Sitecore using Nunit with Sitecore Context information

Few months back, we were doing R&D to implement Unit Testing for our Sitecore project. We tried different kind of solutions like Miscosoft’s Unit Testing Template which we can create from Visual Studio directly and Nunit for which you can install Nuget Package from Visual Studio.

Both has all the functionality that we require in Unit Testing with some different gesture. Microsoft’s Unit Testing project can easily be run from Visual Studio itself and there are couple of ways to run Nunit either by command line or using GUI. I would not go into detail of implementing it.

What is the challenge?

Everything works well in either of two solutions until Sitecore Context comes into the picture. In our case, all the module were tightly coupled so it was not properly unit testable without Sitecore Context information. And we were also needed to perform testing on live items so Fake DB couldn’t help. So, we created Unit Test project using NUnit and executed these unit tests using a tool page from inside Sitecore website with Sitecore Context information. Please see implementation below:

Step 1: Creating Unit Test peoject using NUnit

  • Create a Class Library project, we will call it “MyProject.Tests” here.
  • Add reference of “Sitecore.Kernal.dll” to the project.
  • Install NUnit from Nuget package manager console or download latest NUnit asemplys from download page.
  • Add references of “nunit.core.dll”, “nunit.core.interfaces.dll”, and “nunit.framework.dll” to the project.
  • Create a class and tests as shown in below code:
using NUnit.Framework;
namespace MyProject.Tests
{
    [TestFixture, Category("TestGroup1")]
    public class TestMethods
    {
        [Test]
        public void Test1()
        {
            //Use Sitecore Context information here. It really works!
            String ContextSite = Sitecore.Context.Site.Name;
            String ContextItemName = Sitecore.Context.Item.Name;
            Assert.IsNotNullOrEmpty(ContextItemName, "Cannot access Sitecore Context information.");
        }
    }
}

Step 2: Create aspx page into Sitecore website to execute Tests manually

After created Unit Test project, It’s turn to execute these tests. In place of traditional way of executing either from command line or from GUI of NUnit we will execute it using code from “.aspx” page within Sitecore website.

  • Create an “.aspx” page in your sitecore website, we will call it “ExecuteUnitTest.aspx” here.
  • Add references of “nunit.core.dll”, “nunit.core.interfaces.dll”, and “nunit.framework.dll” to the website as well.
using NUnit.Core;
using NUnit.Core.Filters;
Inherit NUnit.Core.EventListner to the page.
public partial class ExecuteUnitTest : System.Web.UI.Page, EventListener
namespace website.tools
{
    public partial class ExecuteUnitTest : System.Web.UI.Page, EventListener
    {
        #region Member Variables
        DataTable m_results = new DataTable();
        private int m_executedCount = 0;
        private int m_failedCount = 0;
        private TestSuite m_testSuite = null;
        #endregion

        protected void Page_Load(object sender, EventArgs e)
        {
            // Initialise data table to hold test results
            m_results.Columns.Add("test");
            m_results.Columns.Add("result");
            m_results.Columns.Add("message");
            m_results.Columns.Add("class");

            // Initialise controls
            lblResult.Text = "";
            ltlStats.Text = "";

            // Initialise NUnit
            CoreExtensions.Host.InitializeService();

            // Find tests in current assembly
            TestPackage package = new TestPackage(Server.MapPath("~/bin/MyProject.Tests.dll")); // PATH TO THE DLL OF THE UNIT TEST PROJECT
            m_testSuite = new TestSuiteBuilder().Build(package);

            if (!IsPostBack)
            {
                // Display category filters
                StringCollection coll = new StringCollection();
                GetCategories((TestSuite)m_testSuite, coll);
                string[] cats = new string[coll.Count];
                coll.CopyTo(cats, 0);
                Array.Sort(cats);
                cblCategories.DataSource = cats;
                cblCategories.DataBind();
            }
        }

        protected void RunClick(object sender, EventArgs args)
        {
            // Determine if any category filters have been selected
            StringCollection categories = new StringCollection();
            for (int i = 0; i < cblCategories.Items.Count; i++)             {                 if (cblCategories.Items[i].Selected)                     categories.Add(cblCategories.Items[i].Value);             }             string[] arCats = new string[categories.Count];             categories.CopyTo(arCats, 0);             // Create a category filter             ITestFilter filter = new CategoryFilter(arCats);             //ITestFilter filter = new NUnit.Core.Filters.SimpleNameFilter("GetExternalContentAndTransform");             TestResult result = null;             // Run test suite with appropriate filter             if (arCats.Length >= 1)
                result = m_testSuite.Run(this, filter);
            else
                result = m_testSuite.RunSuite(this, NUnit.Core.Filters.SimpleNameFilter.Empty);
            //result = m_testSuite.Run(this, NUnit.Core.Filters.SimpleNameFilter.Empty);

            // Bind results to presentation
            DataView m_resultsview = new DataView(m_results);
            DataTable dt = m_resultsview.ToTable(true, "test");
            gvResults.DataSource = m_results;
            gvResults.DataBind();

            // Display statistics
            ltlStats.Text = string.Format("{0} out of {1} tests run in {2} seconds.", m_executedCount, result.Test.TestCount, result.Time);

            if (m_failedCount > 0)
                ltlStats.Text += string.Format("
{0} {1} failed", m_failedCount, m_failedCount == 1 ? "test" : "tests");

            int skipped = result.Test.TestCount - m_executedCount;
            if (skipped > 0)
                ltlStats.Text += string.Format("
{0} {1} skipped", skipped, skipped == 1 ? "test" : "tests");

            lblResult.Text = "Suite " + (result.IsSuccess ? "Passed" : "Failed");
            if (result.IsSuccess)
                lblResult.CssClass = "passLabel";
            else
                lblResult.CssClass = "failLabel";
        }

        ///
<summary>
        /// Find all available categories in the test suite
        /// </summary>

        /// <param name="suite">The test suite to get categories from</param>
        /// <param name="cats">Output collection containing categories found</param>
        private void GetCategories(TestSuite suite, StringCollection cats)
        {
            if (suite.Categories != null)
            {
                for (int i = 0; i < suite.Categories.Count; i++)
                    if (!cats.Contains((string)suite.Categories[i]))
                        cats.Add((string)suite.Categories[i]);
            }

            for (int i = 0; i < suite.Tests.Count; i++)
                if (((ITest)suite.Tests[i]).IsSuite)
                    GetCategories((TestSuite)suite.Tests[i], cats);
        }

        #region EventListener Members

        public void TestFinished(TestResult result)
        {
            // Put results into data table
            DataRow dr = m_results.NewRow();
            dr["test"] = result.Test.TestName;
            dr["message"] = result.Message;
            if (result.IsFailure)
                dr["message"] += result.StackTrace;
            dr["class"] = "notRun";

            if (result.IsSuccess && result.Executed)
            {
                dr["result"] = "Pass";
                dr["class"] = "pass";
            }

            if (result.IsFailure && result.Executed)
            {
                dr["result"] = "Fail";
                dr["class"] = "fail";
                m_failedCount++;
            }

            if (result.Executed)
                m_executedCount++;

            m_results.Rows.Add(dr);
        }

        public void RunFinished(Exception exception)
        {
        }

        public void RunFinished(TestResult result)
        {
        }

        public void RunStarted(string name, int testCount)
        {
        }

        public void SuiteFinished(TestResult result)
        {
        }

        public void SuiteStarted(TestName testName)
        {
        }

        public void TestOutput(TestOutput testOutput)
        {
        }

        public void TestStarted(TestName testName)
        {
        }

        public void UnhandledException(Exception exception)
        {
        }

        #endregion
    }
}

When you view above page in the browser using link http://#MySitecoreDomain#/tools/#ExecuteUnitTest.aspx#,
You will see all the categories specified in the Unit Testing project. Upon selecting one or more
selecting when you click submit, It will run all the test suites available within that category
and displays the result of the tests as shown in below image.

UnitTest1
After executing suite, it looks like below:

UnitTest2
And thus way you can write the tests which is highly dependent on Sitecore Context information.

Enjoy Unit Testing with Sitecore Context. No Fake 🙂

Useful Sitecore Recourses

Long way back when i started working with Sitecore, I have faced many difficulties to get the useful resources. Even though there are lots of great writers available in the Sitecore world, It’s difficult to find what each said on a same topic.

To overcome this i am trying to make a single repository, where we can have most useful links of the content written by great Sitecore people on a specific topic. so that for specific topic we only need to look at one place.

If you wish to contribute to the repository, please get in touch with me at psatikunvar7@gmail.com 

Topics:

Sitecore Publishing

Sitecore Caching

Sitecore Search –  Lucene/Solr

Workflows – developing and customizing

Globalization and Language Fallback Support

Custom Field Types

Custom Pipelines

Sitecore Modules on Marketplace

DMS – Implementing and customising Engagement Analytics

Note that i have just started collecting useful resources for different topics (Please forgive me if i have missed other useful links), and it will last for as long as Sitecore 🙂

Please share the topics and useful links for that topic to get added to this repository.

EvoPDF/Winnovative – Adding Header, Footer, and Page Number in Existing PDF without using HtmlToPdfConverter

Adding to my previous blog post on using EvoPDF/Winnovative to convert Html to PDF, How we can add Header, Footer, and Page Number in existing PDFs.

When you look examples given by EvoPDF/Winnovative for adding Header/Footer/Page Number in existing PDF, Most of examples are with HtmlToPdfConverter. Which means example of existing PDFs and also converting URL/Html to PDF at a time.

But if we do not want to do any conversion, Just add Header/Footer/Page Number in existing PDF document without using HtmlToPdfConverter than there isn’t any solution documented. So, here we will see how we can achieve this functionality:

Merge Existing PDFs & Add Header/Footer/Page Numbers

 //Create a document to merge all selected PDFs
 Document MergedDocument = new Document();

 //Get individual existing PDFs to merge and add header/footer/page number
 Document PDFDoc1 = new Document(Server.MapPath("~/PDF1.pdf"));
 Document PDFDoc2 = new Document(Server.MapPath("~/PDF2.pdf"));

 //Merge existing PDFs into New Merge Document
 MergedDocument.AppendDocument(PDFDoc1, true, true, true);
 MergedDocument.AppendDocument(PDFDoc2, true, true, true);
 //Appending document with this syntax MergedDocument.AppendDocument(PDFDoc1);
 //will not add the header/footer/page number on the PDF. To add it properly,
 //you need to append document in above syntax Doc.AppendDocument(PDFDoc,
 //enableHeaderAndFooter, drawHeaderOnFirstPage, drawFooterOnFirstPage)

 //Append Header, Footer and Page Number to the merged document so that it will get
 //applied to all existing PDFs appended to the document           
 CreateHeader(MergedDocument, 100, "<h3>Header</h3>", False, "Page &p; of &P;", 10, 60, "Verdana", 10, "Silver", True, "Silver");
 CreateFooter(MergedDocument, 100, "<h3>Footer</h3>", True, "Page &p; of &P;", 10, 60, "Verdana", 10, "Silver", True, "Silver");
            
 byte[] outPdfBuffer = MergedDocument.Save();
 Response.AddHeader("Content-Type", "application/pdf");
 Response.AddHeader("Content-Disposition", String.Format("attachment;  filename=Header_Footer_in_External_PDF.pdf; size={0}", outPdfBuffer.Length.ToString()));
 Response.BinaryWrite(outPdfBuffer);
 Response.End();

/// <summary>
/// Creates the document header
/// </summary>
 private void CreateHeader(Document pdfDocument, int headerHeight, string   headerHtml, bool addPageNumbers, string pageNumberText, int pageNumberLocationX,
int pageNumberLocationY, string pageNumberFontFamily, int pageNumberFontSize, string pageNumberFontColor, bool drawHeaderLine, string headerLineColor)
        {
            pdfDocument.AddHeaderTemplate(headerHeight);
            HtmlToPdfElement HtmlElement = new HtmlToPdfElement(headerHtml, "");
            HtmlElement.FitHeight = true;
            pdfDocument.Header.AddElement(HtmlElement);
            if (addPageNumbers)
            {
                TextElement pageNumberElement = new TextElement(pageNumberLocationX, pageNumberLocationY, pageNumberText,
                    new System.Drawing.Font(new System.Drawing.FontFamily(pageNumberFontFamily), pageNumberFontSize, System.Drawing.GraphicsUnit.Point));
                pageNumberElement.ForeColor = Color.FromName(pageNumberFontColor);
                pageNumberElement.EmbedSysFont = true;
                pdfDocument.Header.AddElement(pageNumberElement);
            }
            if (drawHeaderLine)
            {
                float Width = pdfDocument.Header.Width;
                float Height = pdfDocument.Header.Height;
                LineElement headerLine = new LineElement(0, Height - 1, Width, Height - 1);
                headerLine.ForeColor = Color.FromName(headerLineColor);
                pdfDocument.Header.AddElement(headerLine);
            }
        }
/// <summary>
/// Creates the document footer
/// </summary>
 private void CreateFooter(Document pdfDocument, int footerHeight, string footerHtml, bool addPageNumbers, string pageNumberText, int pageNumberLocationX,
int pageNumberLocationY, string pageNumberFontFamily, int pageNumberFontSize, string pageNumberFontColor, bool drawFooterLine, string footerLineColor)
        {
            pdfDocument.AddFooterTemplate(footerHeight);
            HtmlToPdfElement HtmlElement = new HtmlToPdfElement(footerHtml, "");
            HtmlElement.FitHeight = true;
            pdfDocument.Footer.AddElement(HtmlElement);
            if (addPageNumbers)
            {
                TextElement pageNumberElement = new TextElement(pageNumberLocationX, pageNumberLocationY, pageNumberText,
                    new System.Drawing.Font(new System.Drawing.FontFamily(pageNumberFontFamily), pageNumberFontSize, System.Drawing.GraphicsUnit.Point));
                pageNumberElement.ForeColor = Color.FromName(pageNumberFontColor);
                pageNumberElement.EmbedSysFont = true;
                pdfDocument.Footer.AddElement(pageNumberElement);
            }
            if (drawFooterLine)
            {
                float Width = pdfDocument.Footer.Width;
                LineElement footerLine = new LineElement(0, 0, Width, 0);
                footerLine.ForeColor = Color.FromName(footerLineColor);
                pdfDocument.Footer.AddElement(footerLine);
            }
        }

 

This might help you if you are stuck in same situation, Please share if any other way with which we can implement this functionality.

Thanks for reading 🙂

EvoPDF – Merging PDFs, Editing existing PDF, and Giving internal link

You may have faced several scenarios where you need a functionality to be develop in which you need to convert html – a web page into PDF.

There are several third party dlls available for conversion from html to pdf in Asp.Net. Among those you can consider EvoPDF/Winnovative as one of the best option having large variety of functionality available. Click here for more information on EvoPDF.

You can see from the link provided above for EvoPDF, they have covered many functionalities with example and sample code. still it’s a large globe and we may find some situation for which we may need to struggle a little bit. I am sharing here few functionality which i have encountered recently and at the end everything working like a charm.

Merging PDFs

Here, we will see basic functionality to create PDF from html and merging it with some existing PDF available to generate a new merged PDF.

You needed to import any of below libraries to begin with:


using Winnovative;
Or
using EvoPdf.HtmlToPdf;

Document MergeResultPdfDocument = new Document();
Document ExistingPdfDocument = new Document();
Document HtmlToPDFDocument = new Document(); 

//Reading Existing file in Document object
Byte[] ExistingPDF = File.ReadAllBytes(fileName);
using (Stream Stream = new MemoryStream(ExistingPDF))
{
   ExistingPdfDocument = new Document(loStream);
   //Adding existing PDF file to Merged PDF 
   MergeResultPdfDocument.AppendDocument(ExistingPdfDocument);
} 

//Convert HtmlToPdf and Merge PDF
PdfConverter Converter = new PdfConverter();
Converter.LicenseKey = LICENSEKEY;
HtmlToPDFDocument = Converter.GetPdfDocumentObjectFromUrl(&amp;quot;URL to convert&amp;quot;);
MergeResultPdfDocument.AppendDocument(HtmlToPDFDocument); 

Generate PDF from Html, Edit Runtime, and Give InternalLink

This is an interesting task. Where you want to generate a PDF from Html and wanted to edit it using code based on some conditions before generating PDF. We will see here how in two steps we can achieve this.

For ex: create a PDF Document from URL (as shown above) having below html:

<table>
<tbody>
<tr>
<td>
              <span data-mapping-enabled="true" style="font-size: 18px; font-weight: bold; color: navy">
			#INDEX1#
              </span></td>
</tr>
<tr>
<td>
              <span data-mapping-enabled="true" style="font-size: 18px; font-weight: bold; color: navy">
			#INDEX2#
              </span></td>
</tr>
<tr>
<td>
              <span data-mapping-enabled="true" style="font-size: 18px; font-weight: bold; color: navy">
			#INDEX3#
              </span></td>
</tr>
</tbody>
</table>

Here, data-mapping-enabled=”true” is very important attribute, using which we can extract those element from PDF and we can update it.

Now, edit the response as per requirement and generate PDF from the final response.

string response = GetResponse("URL to convert");
//Make required changes in response text. We will update here #INDEX# with proper title.

For(int i=0; i<3; i++) // As we have three records in html. this can be any number dynamically.
{
   response = response.replace("#Index" + (i + 1) + "#", Title[i]);
}

//After editing response, create the PDF from final response
PdfConverter htmlToPdfConverter = new PdfConverter();
htmlToPdfConverter.LicenseKey = LICENSEKEY;

Document IndexPdfDocument = htmlToPdfConverter.GetPdfDocumentObjectFromHtmlString(response);

After generating PDF, now we will give internal link to some page to the title. So, we can create a functionality similar to the index page. where we can click on index title to navigate to that page.


//get all html elements which are marked using <strong>data-mapping-enabled="true"</strong>

foreach (HtmlElementMapping htmlElementInfo in htmlToPdfConverter.HtmlElementsMappingOptions.HtmlElementsMappingResult)
                {
                    HtmlElementPdfRectangle[] htmlElementRectanglesInPdf = htmlElementInfo.PdfRectangles;
                    for (int i = 0; i < htmlElementRectanglesInPdf.Length; i++)
                    {
                        int pdfPageIndex = htmlElementRectanglesInPdf[i].PageIndex;
                        RectangleF rectangleInPdfPage = htmlElementRectanglesInPdf[i].Rectangle;

                        //add a rectangle of height 10px and with 1000px at given title to create link
                        RectangleF linkRectangle = new RectangleF(0, rectangleInPdfPage.Y, 1000, 10);

                        //Create explicit destination object to the page number you want to link
                        ExplicitDestination PageDestination = new ExplicitDestination(MergeResultPdfDocument.Pages[pageindex[count]], new PointF(0, 0));

                        //Create Internal Link element and add this element to index page
                        InternalLinkElement internalLink = new InternalLinkElement(linkRectangle, PageDestination);
                       
        IndexPdfDocument.Pages[pdfPageIndex].AddElement(internalLink);
                    }
                    count++;
                }

MergeResultPdfDocument.InsertDocument(0, IndexPdfDocument);

This is very important section of code where you identify the html elements from existing PDF, Creates a rectangle at place of html element, and insert an internal link element.

That’s it, And Wish you all a very happy new year 2016.

Common GUIDs used in Sitecore

While developing a web application with sitecore, we uses many things from template creation to item creation in sitecore. Here, i have listed common Template IDs and Item IDs that we can use to search/identify/use particular item/template.

Common Template GUIDs


    /// <summary>
    /// The ID of 'Sitecore Client/Applications/Application'.
    /// </summary>
    public static readonly ID Application = new ID("{EB06CEC0-5E2D-4DC4-875B-01ADCC577D13}");
    /// <summary>
    /// The ID of 'System/Alias'.
    /// </summary>
    public static readonly ID Alias = new ID("{54BCFFB7-8F46-4948-AE74-DA5B6B5AFA86}");
    /// <summary>
    /// The ID of 'System/Archiving/Archived item'.
    /// </summary>
    public static readonly ID ArchivedItem = new ID("{BF2B8DA2-3CBA-485D-8F85-3788B8AFBDBF}");
    /// <summary>
    /// The ID of 'Commands/Command item'.
    /// </summary>
    public static readonly ID Command = new ID("{A66F4A32-23A6-4AC3-AB14-84F383C5F3BA}");
    /// <summary>
    /// The ID of 'Commands/CommandGroup item'.
    /// </summary>
    public static readonly ID CommandGroup = new ID("{FBDD7D4F-3300-4432-9CB1-FDAD551DDD5E}");
    /// <summary>
    /// The ID of 'System/Masters/Command Master'.
    /// </summary>
    public static readonly ID CommandMaster = new ID("{B2613CC1-A748-46A3-A0DB-3774574BD339}");
    /// <summary>
    /// The ID of 'System/Layout/Device'.
    /// </summary>
    public static readonly ID Device = new ID("{B6F7EEB4-E8D7-476F-8936-5ACE6A76F20B}");
    /// <summary>
    /// The ID of 'System/Dictionary/DictionaryEntry'.
    /// </summary>
    public static readonly ID DictionaryEntry = new ID("{6D1CD897-1936-4A3A-A511-289A94C2A7B1}");
    /// <summary>
    /// The ID of 'System/Dictionary/Dictionary Domain'
    /// </summary>
    public static readonly ID DictionaryDomain = new ID("{0A2847E6-9885-450B-B61E-F9E6528480EF}");
    /// <summary>
    /// The ID of 'System/Security/Domain'.
    /// </summary>
    public static readonly ID Domain = new ID("{438F33BA-504D-4EFB-BE78-42B98603A7E8}");
    /// <summary>
    /// The ID of 'System/Masters/Dynamic Master'.
    /// </summary>
    public static readonly ID DynamicMaster = new ID("{B4D19D07-B3EB-4F7D-98EC-8BCB41CCC58E}");
    /// <summary>
    /// The ID of 'Folder'.
    /// </summary>
    public static readonly ID Folder = new ID("{A87A00B1-E6DB-45AB-8B54-636FEC3B5523}");
    /// <summary>
    /// The ID of 'Help Text'.
    /// </summary>
    public static readonly ID HelpText = new ID("{11A111FF-4343-4AF8-91DC-3C49DBEDD9C6}");
    /// <summary>
    /// The ID of 'Versioned/Image'.
    /// </summary>
    public static readonly ID Image = new ID("{C97BA923-8009-4858-BDD5-D8BE5FCCECF7}");
    /// <summary>
    /// The ID of 'System/Language'.
    /// </summary>
    public static readonly ID Language = new ID("{F68F13A6-3395-426A-B9A1-FA2DC60D94EB}");
    /// <summary>
    /// The ID of 'System/Layout/Layout'.
    /// </summary>
    public static readonly ID Layout = new ID("{3A45A723-64EE-4919-9D41-02FD40FD1466}");
    /// <summary>
    /// The ID of 'System/Layout/Layout group'.
    /// </summary>
    public static readonly ID LayoutGroup = new ID("{85B7F5D9-6F3A-4AD1-B218-D9FBE1DF8BB3}");
    /// <summary>
    /// The ID of 'System/LinkedDatabase'.
    /// </summary>
    public static readonly ID LinkedDatabase = new ID("{2085BFB3-1371-4092-BF06-32EF5849ED87}");
    /// <summary>
    /// The ID of 'MainSection'.
    /// </summary>
    public static readonly ID MainSection = new ID("{E3E2D58C-DF95-4230-ADC9-279924CECE84}");
    /// <summary>
    /// The ID of 'System/Branches/Branch'.
    /// </summary>
    public static readonly ID BranchTemplate = new ID("{35E75C72-4985-4E09-88C3-0EAC6CD1E64F}");
    /// <summary>
    /// The ID of 'System/Branches/Branch Folder'.
    /// </summary>
    public static readonly ID BranchTemplateFolder = new ID("{85ADBF5B-E836-4932-A333-FE0F9FA1ED1E}");
    /// <summary>
    /// The ID of 'Media folder'.
    /// </summary>
    public static readonly ID MediaFolder = new ID("{FE5DD826-48C6-436D-B87A-7C4210C7413B}");
    /// <summary>
    /// The ID of 'System/Menus/Menu Divider'.
    /// </summary>
    public static readonly ID MenuDivider = new ID("{35753BF3-8A94-4DA6-A5D7-DBD945D1AA59}");
    /// <summary>
    /// The ID of 'System/Menus/Menu Item'.
    /// </summary>
    public static readonly ID MenuItem = new ID("{998B965E-6AB8-4568-810F-8101D60D0CC3}");
    /// <summary>
    /// The ID of 'Node'.
    /// </summary>
    public static readonly ID Node = new ID("{239F9CF4-E5A0-44E0-B342-0F32CD4C6D8B}");
    /// <summary>
    /// The ID of 'Packages/Package registration'.
    /// </summary>
    public static readonly ID PackageRegistration = new ID("{22A11D20-5F1D-4216-BF3F-18C016F1F98E}");
    /// <summary>
    /// The ID of 'Property'.
    /// </summary>
    public static readonly ID Property = new ID("{97D75760-CF8B-4740-810B-7727B564EF4D}");
    /// <summary>
    /// The ID of 'System/Proxy'.
    /// </summary>
    public static readonly ID Proxy = new ID("{CB3942DC-CBBA-4332-A7FB-C4E4204C538A}");
    /// <summary>
    /// The ID of 'System/Reference'.
    /// </summary>
    public static readonly ID Reference = new ID("{EF295CD8-19D4-4E02-9438-94C926EF5284}");
    /// <summary>
    /// The ID of 'System/Layout/Rendering group'.
    /// </summary>
    public static readonly ID RenderingGroup = new ID("{4B8AD536-4FA6-4122-A31E-32BB6BC42806}");
    /// <summary>
    /// The ID of the 'Security/Role'.
    /// </summary>
    public static readonly ID Role = new ID("{A7DF04B4-4C4B-44B7-BE1E-AD901BD53DAD}");
    /// <summary>
    /// The ID of 'System/Tasks/Schedule'.
    /// </summary>
    public static readonly ID Schedule = new ID("{70244923-FA84-477C-8CBD-62F39642C42B}");
    /// <summary>
    /// The ID of 'System/Standard template'.
    /// </summary>
    public static readonly ID StandardTemplate = new ID("{1930BBEB-7805-471A-A3BE-4858AC7CF696}");
    /// <summary>
    /// The ID of 'Sublayout'.
    /// </summary>
    public static readonly ID Sublayout = new ID("{0A98E368-CDB9-4E1E-927C-8E0C24A003FB}");
    /// <summary>
    /// The ID of 'System/Template'.
    /// </summary>
    public static readonly ID Template = new ID("{AB86861A-6030-46C5-B394-E8F99E8B87DB}");
    /// <summary>
    /// The ID of the 'System/Template field'.
    /// </summary>
    public static readonly ID TemplateField = new ID("{455A3E98-A627-4B40-8035-E683A0331AC7}");
    /// <summary>
    /// The ID of the 'System/Template field type'.
    /// </summary>
    public static readonly ID TemplateFieldType = new ID("{F8A17D6A-118E-4CD7-B5F5-88FF37A4F237}");
    /// <summary>
    /// The ID of 'System/Template Folder'.
    /// </summary>
    public static readonly ID TemplateFolder = new ID("{0437FEE2-44C9-46A6-ABE9-28858D9FEE8C}");
    /// <summary>
    /// The ID of the 'System/Template section'.
    /// </summary>
    public static readonly ID TemplateSection = new ID("{E269FBB5-3750-427A-9149-7AA950B49301}");
    /// <summary>
    /// The ID of the 'Security/User'.
    /// </summary>
    public static readonly ID User = new ID("{642C9A7E-EE31-4979-86F0-39F338C10AFB}");
    /// <summary>
    /// The ID of 'Versioned/Image'.
    /// </summary>
    public static readonly ID VersionedImage = new ID("{C97BA923-8009-4858-BDD5-D8BE5FCCECF7}");
    /// <summary>
    /// The ID of 'Unversioned/Image'.
    /// </summary>
    public static readonly ID UnversionedImage = new ID("{F1828A2C-7E5D-4BBD-98CA-320474871548}");
    /// <summary>
    /// The ID of the 'System/Workflow/Workflow'.
    /// </summary>
    public static readonly ID Workflow = new ID("{1C0ACC50-37BE-4742-B43C-96A07A7410A5}");
    /// <summary>
    /// The ID of the 'System/Workflow/Command'.
    /// </summary>
    public static readonly ID WorkflowCommand = new ID("{CB01F9FC-C187-46B3-AB0B-97A8468D8303}");
    /// <summary>
    /// The ID of the 'System/Workflow/State'.
    /// </summary>
    public static readonly ID WorkflowState = new ID("{4B7E2DA9-DE43-4C83-88C3-02F042031D04}");
    /// <summary>
    /// The ID of the 'XSL rendering'.
    /// </summary>
    public static readonly ID XSLRendering = new ID("{F1F1D639-4F54-40C2-8BE0-81266B392CEB}");
    /// <summary>
    /// The ID of 'System/Layout/XML Layout'.
    /// </summary>
    public static readonly ID XMLLayout = new ID("{1163DA83-B2EF-4381-BF09-B2FF714B1B3F}");
    /// <summary>
    /// The ID of all MediaItems.
    /// 
    /// </summary>
    public static readonly ID File = new ID("{611933AC-CE0C-4DDC-9683-F830232DB150}");
    /// <summary>
    /// The ID of Preset Persona.
    /// 
    /// </summary>
    public static readonly ID PresetPersona = new ID("{448C4D57-F0F1-4278-8AB8-93DB46C94F1B}");
    /// <summary>
    /// The ID of Preset.
    /// 
    /// </summary>
    public static readonly ID Preset = new ID("{0FC09EA4-8D87-4B0E-A5C9-8076AE863D9C}");    

Common Item GUIDs


    /// <summary>
    /// The Anonymous user ID.
    /// </summary>
    public static readonly ID AnonymousUser = new ID("{4AF789F7-750F-45C1-B4F0-669A6348482E}");
    /// <summary>
    /// The ID of the /sitecore/system/Settings/Rules/Conditional Renderings/Global Rules.
    /// </summary>
    public static readonly ID ConditionalRenderingsGlobalRules = new ID("{6892B190-D0C8-4628-A179-24D197AB0C07}");
    /// <summary>
    /// The ID of "/sitecore/content"
    /// </summary>
    public static readonly ID ContentRoot = new ID("{0DE95AE4-41AB-4D01-9EB0-67441B7C2450}");
    /// <summary>
    /// The ID of "/sitecore/content/Applications/Content Editor/Ribbons/Ribbons/Default"
    /// </summary>
    public static readonly ID DefaultRibbon = new ID("{073BBB5D-65B5-485F-A1F8-64E55C84696E}");
    /// <summary>
    /// The ID of "/sitecore/layout/Devices"
    /// </summary>
    public static readonly ID DevicesRoot = new ID("{E18F4BC6-46A2-4842-898B-B6613733F06F}");
    /// <summary>
    /// The ID of "/sitecore/system/Dictionary"
    /// </summary>
    public static readonly ID Dictionary = new ID("{504AE189-9F36-4C62-9767-66D73D6C3084}");
    /// <summary>
    /// The ID of the 'Everyone' role.
    /// </summary>
    public static readonly ID EveryoneRoleID = new ID("{00088163-665D-4F6F-9E63-C0CF1FB4E2FE}");
    /// <summary>
    /// The ID of the '/sitecore/system/language' item.
    /// </summary>
    public static readonly ID LanguageRoot = new ID("{64C4F646-A3FA-4205-B98E-4DE2C609B60F}");
    /// <summary>
    /// The ID of "/sitecore/layout"
    /// </summary>
    public static readonly ID LayoutRoot = new ID("{EB2E4FFD-2761-4653-B052-26A64D385227}");
    /// <summary>
    /// The ID of "/sitecore/layout/layouts"
    /// </summary>
    public static readonly ID Layouts = new ID("{75CC5CE4-8979-4008-9D3C-806477D57619}");
    /// <summary>
    /// The ID of "/sitecore/templates/branches"
    /// </summary>
    public static readonly ID BranchesRoot = new ID("{BAD98E0E-C1B5-4598-AC13-21B06218B30C}");
    /// <summary>
    /// The ID of "/sitecore/media library"
    /// </summary>
    public static readonly ID MediaLibraryRoot = new ID("{3D6658D8-A0BF-4E75-B3E2-D050FABCF4E1}");
    /// <summary>
    /// The Null ID.
    /// </summary>
    public static readonly ID Null = new ID("{00000000-0000-0000-0000-000000000000}");
    /// <summary>
    /// The ID of "/sitecore/layout/Placeholders"
    /// </summary>
    public static readonly ID PlaceholderSettingsRoot = new ID("{1CE3B36C-9B0C-4EB5-A996-BFCB4EAA5287}");
    /// <summary>
    /// The ID of the Sitecore root item.
    /// </summary>
    public static readonly ID RootID = new ID("{11111111-1111-1111-1111-111111111111}");
    /// <summary>
    /// The ID of the root item of the system/policies section
    /// </summary>
    public static readonly ID Policies = new ID("{1E7C8D5A-51CF-42A7-8D58-0752B3E39C8B}");
    /// <summary>
    /// The ID of the root item of the templates section
    /// </summary>
    public static readonly ID TemplateRoot = new ID("{3C1715FE-6A13-4FCF-845F-DE308BA9741D}");
    /// <summary>
    /// The ID of the root item of the system/workflows section
    /// </summary>
    public static readonly ID WorkflowRoot = new ID("{05592656-56D7-4D85-AACF-30919EE494F9}");
    /// <summary>
    /// The ID of the /sitecore/content/System/Shell item in the core database
    /// </summary>
    public static readonly ID Shell = new ID("{4616E2BE-BF68-4D22-91B3-93301C9F86B7}");
    /// <summary>
    /// The ID of the /sitecore/content/System/Shell/__All in the core database
    /// </summary>
    public static readonly ID ShellAll = new ID("{DF4F23E3-9BAC-42D6-A249-E50CA7475FFD}");
    /// <summary>
    /// The ID of the /sitecore/content/System/Shell/__Default in the core database
    /// </summary>
    public static readonly ID ShellDefault = new ID("{A8653DDD-862E-418F-A312-BD543157E354}");
    /// <summary>
    /// The ID of "/sitecore/system"
    /// </summary>
    public static readonly ID SystemRoot = new ID("{13D6D6C6-C50B-4BBD-B331-2B04F1A58F21}");
    /// <summary>
    /// ID indicating 'undefined' value.
    /// </summary>
    public static readonly ID Undefined = new ID("{FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF}");
    /// <summary>
    /// ID indicating '/sitecore/system/Marketing Center/Campaigns' value.
    /// </summary>
    public static readonly ID Campaigns = new ID("{EC095310-746F-4C1B-A73F-941863564DC2}");
    /// <summary>
    /// ID indicating '/sitecore/system/Marketing Center/Goals' value.
    /// </summary>
    public static readonly ID Goals = new ID("{0CB97A9F-CAFB-42A0-8BE1-89AB9AE32BD9}");
    /// <summary>
    /// ID indicating '/sitecore/system/Marketing Center/Presentation/Policies' value.
    /// </summary>
    public static readonly ID Policies = new ID("{DB40C9D3-5DB3-4831-A0A9-53AB17EED652}");
    /// <summary>
    /// ID indicating "/sitecore/system/Marketing Center/Reports/Report Filters" value.
    /// </summary>
    public static readonly ID ReportFilters = new ID("{5B3FE22D-1DC9-4CC4-9665-1A3F2DDD6732}");
    /// <summary>
    /// ID indicating '/sitecore/system/Marketing Center/Test Laboratory' value.
    /// </summary>
    public static readonly ID TestLaboratory = new ID("{BA1B87AC-0853-45F0-AE13-41F969540134}");

Jquery Datatable: Implementing Load on demand Server side with PageMethod/WebMethod

Jquery Datatable is one of the best plugin which we can use in alternate of GridView.

Though there are so many examples available at https://www.datatables.net/ for sever side processing with .txt or .php as AjaxSource. But there isn’t full example on achieving Load on demand with server side processing in asp.net by using PageMethod/WebMethod.

So, if you are looking for similar solution, please walk through below sample code.

Important: Before jumping into the code, it can be beneficial if you have some knowledge of datatable terminology and parameters we send to PageMethod/WebMethod or Parameters we return from PageMethod/WebMethod.

Click here for more information on Parameters sent to the server and returned from server.

Click here for more information on Datatable Methods.

CSS & JS

<link href="//cdn.datatables.net/1.10.7/css/jquery.dataTables.min.css" rel="stylesheet" type="text/css" />
<script src="//cdn.datatables.net/1.10.7/js/jquery.dataTables.min.js" type="text/javascript"></script>

Default.aspx

<form id="form1" runat="server">
        <div id="container">
            <table id="JQtblUsers" class="display">
                <thead>
                    <tr>
                        <th>Email</th>
                        <th>First Name</th>
                        <th>Last Name</th>
                        <th>Company</th>
                    </tr>
                </thead>
                <tbody>
                </tbody>
            </table>
        </div>
    </form>
<script type="text/javascript">
        $(document).ready(function () {
            var oTable = $('#JQtblUsers').dataTable({
                "paging": true,
                "sPaginationType": "full_numbers",
                "bServerSide": true,
                "sAjaxSource": "Default3.aspx/GetUsers",
                "fnServerData": function (sSource, aoData, fnCallback) {
                    logsRequest = $.ajax({
                        type: "POST",
                        url: sSource,
                        data: "{'sEcho': '" + getValueFromArray(aoData, "sEcho") + "', 'sSearch': '" + getValueFromArray(aoData, "sSearch")
                            + "', 'iDisplayLength': '" + getValueFromArray(aoData, "iDisplayLength") + "', 'iDisplayStart': '" + getValueFromArray(aoData, "iDisplayStart")
                            + "', 'iColumns': '" + getValueFromArray(aoData, "iColumns") + "', 'iSortingCols': '" + getValueFromArray(aoData, "iSortingCols")
                            + "', 'sColumns': '" + getValueFromArray(aoData, "sColumns") + "'}",
                        contentType: "application/json; charset=utf-8",
                        dataType: "json",
                        success: function (data) {
                            var json = jQuery.parseJSON(data.d);
                            fnCallback(json);
                        }
                    });
                },
                "aoColumns": [
                                {
                                    "sName": "Email",
                                    "bSearchable": true,
                                    "bSortable": true,
                                    "fnRender": function (oObj) {
                                        return '<a href=\"mailto:' + oObj.aData[0] + '\">' + oObj.aData[0] + '</a>';
                                    }
                                },
                                {
                                    "sName": "FirstName",
                                    "bSearchable": true,
                                    "bSortable": true,
                                    "fnRender": function (oObj) {
                                        return oObj.aData[1];
                                    }
                                },
                                {
                                    "sName": "LastName",
                                    "bSearchable": true,
                                    "bSortable": true,
                                    "fnRender": function (oObj) {
                                        return oObj.aData[2];
                                    }
                                },
                                {
                                    "sName": "Company",
                                    "bSearchable": true,
                                    "bSortable": true,
                                    "fnRender": function (oObj) {
                                        return oObj.aData[3];
                                    }
                                }
                ],
            });
        });

        function getValueFromArray(aoData, Key) {
            for (i = 0; i < aoData.length; i++) {
                if (aoData[i].name == Key) {
                    return aoData[i].value;
                }
            }
        }
    </script>

Default.aspx.cs

#region Class

public class Employee
{
    public string Email { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Company { get; set; }
}

#endregion Class
#region Methods

    [WebMethod]
    public static string GetUsers(string sEcho, string sSearch, int iDisplayLength, int iDisplayStart, int iColumns, int iSortingCols, string sColumns)
    {
        var echo = int.Parse(sEcho);
        var displayLength = iDisplayLength;
        var displayStart = iDisplayStart;

        var records = GetRecordsFromDatabaseWithFilter(sSearch);
        if (records == null)
            return string.Empty;

        var itemsToSkip = displayStart == 0 ? 0 : displayStart + 1;
        var pagedResults = records.Skip(itemsToSkip).Take(displayLength).ToList();
        var hasMoreRecords = false;

        var sb = new StringBuilder();
        sb.Append(@"{" + "\"sEcho\": " + echo + ",");
        sb.Append("\"recordsTotal\": " + records.Count + ",");
        sb.Append("\"recordsFiltered\": " + pagedResults.Count + ",");
        sb.Append("\"iTotalRecords\": " + records.Count + ",");
        sb.Append("\"iTotalDisplayRecords\": " + records.Count + ",");
        sb.Append("\"aaData\": [");
        foreach (var result in pagedResults)
        {
            if (hasMoreRecords)
                sb.Append(",");

            sb.Append("[");
            sb.Append("\"" + result.Email + "\",");
            sb.Append("\"" + result.FirstName + "\",");
            sb.Append("\"" + result.LastName + "\",");
            sb.Append("\"" + result.Company + "\"");
            sb.Append("]");
            hasMoreRecords = true;
        }
        sb.Append("]}");
        return sb.ToString();
    }

    public static List<Employee> GetRecordsFromDatabaseWithFilter(string search)
    {
        List<Employee> Employees = new List<Employee>();
        for (int i = 0; i <= 5; i++)
        {
            Employees.Add(new Employee { Email = "psatikunvar7@gmail.com", FirstName = "Pratik", LastName = "Satikunvar", Company = "Apple" + i });
            Employees.Add(new Employee { Email = "psatikunvar7@gmail.com", FirstName = "Pratik", LastName = "Satikunvar", Company = "Microsoft" + i });
            Employees.Add(new Employee { Email = "psatikunvar7@gmail.com", FirstName = "Pratik", LastName = "Satikunvar", Company = "Google" + i });
            Employees.Add(new Employee { Email = "psatikunvar7@gmail.com", FirstName = "Pratik", LastName = "Satikunvar", Company = "Amazon" + i });
        }
        return Employees.Where(a => a.Company.ToLower().Contains(search.ToLower())).ToList();
    }

    #endregion Methods

I hope it was interesting and useful.

Please share any real time issue or feature you have faced or implemented.

Thank You 🙂