Sitecore from Rendering to Experience Editor

In Sitecore, how do you set up a template  and a rendering that works in the Experience editor? Here is the checklist:

STEP 1: CREATE A TEMPLATE

Create the template. For each field, use the “Title” field for all of your languages to display a user friendly name.

Template

Template

STEP 2: CREATE CUSTOM EXPERIENCE BUTTONS

In the CORE database, add a Field Editor Button to the /sitecore/content/Applications/WebEdit/Custom Experience Buttons folder.

Add the fields that are not editable directly from the Experience Editor (or add all fields from your template, it is OK that a field can be edited directly and from a custom button). Use the “Fields” field to add a pipe separated list of field names:

Custom Experience Buttons

Custom Experience Buttons

STEP 3: CREATE AN 128×128 PIXEL IMAGE OF YOUR CONTROL

Sitecore have a “take screenshot” feature, but a stylized image of your control is often better. Create a 128×128 pixel image (.png or .jpg) and upload it to the media library. The image must depict or represent the component you are about to create.

STEP 4: CREATE A RENDERING OR SUBLAYOUT

MVC project creates renderings, older ASPX project creates sublayouts.

Mark the rendering/sublayout as “Editable”.
Point the “Datasource Location” to where the datasource item should be placed. Use query: to select a dynamic location.
Select the template you created in STEP 1 in the “Datasource Template” field.

Sublayout

Sublayout

Select the custom experience button you created in STEP 2 in the “Experience Editor Buttons” field.

Sublayout

Sublayout

The field “Thumbnail” (found when selecting “Standard Fields”, under “Appearance”) is used for the 128×128 pixel image you created earlier.

Sublayout

Sublayout

Finally, use “Display Name” to give the rendering/sublayout a user friendly name. Remember to set a display name for all languages.

Sublayout

Sublayout

STEP 5: SETUP PLACEHOLDER SETTINGS

Add the rendering/sublayout from STEP 4 to the placeholder settings of the placeholders where you are allowed to add this component.

Placeholder Settings

Placeholder Settings

THE END RESULT:

The Placeholder Settings allows you to see the rendering/sublayout. The Thumbnail gives your control a nice presentation, and the Display Name of the rendering gives your control a user friendly name:

Select a Rendering

Select a Rendering

The rendering/sublayout Datasource Location groups the places where the datasource can be created. The Datasource Template locks the sublayout/rendering to one specific template, making it impossible for the editor to select the wrong template.

Select the Associated Content

Select the Associated Content

The Custom Experience Editor Button creates a easy access to edit the content of the rendering/sublayout. And the Title field for the template fields displays a user friendly name.

Editing fields

Editing fields

MORE TO READ:

Advertisements
Posted in General .NET, Sitecore 7, Sitecore 8, Sitecore 9 | Tagged , , , , , | Leave a comment

SHA256 hashing email addresses for GDPR reasons

This is a followup on the previous post C# Mask email address for GDPR reasons, where user Inspector Cluedget pointed out that masking (replacing characters with *) an email address in the log file is the least safest of the data masking approaches available.

This extension method will SHA256 hash the email address and add a fake domain name (to make the string look like an email address).

THE EXTENSION METHOD:

using System.Security.Cryptography;
using System.Text;

namespace MyNamespace
{
  public static class StringFormatter
  {
    public static string MaskEmail(this string s)
    {
      return SHA256(s) + "@domain.com";
    }

    private static string SHA256(string s)
    {
      SHA256Managed sha256 = new SHA256Managed();
      StringBuilder hash = new StringBuilder();
      byte[] hashArray = sha256.ComputeHash(Encoding.UTF8.GetBytes(s));
      foreach (byte b in hashArray)
      {
        hash.Append(b.ToString("x"));
      }
      return hash.ToString();
    }
  }
}

USAGE:

using MyNamespace;
 
public void TestMethod()
{
  string email = "someperson@somedomain.com";
  string maskedEmail = email.MaskEmail();
  // result: 14683d88281fc3ad43f39f8ceab111c96cc145be2a3feec98f914661f18d@domain.com
}

WHY?

With the new GDPR rules you must be very careful when storing emails or other personal information anywhere, including your log files. And you should never give out a log file containing email addresses to a third party, even when this third party is “just helping you with a totally unrelated code bug elsewhere”.

There are many approaches to ensure GDPR compliance. The best way is to remove any personal data from any log file. This is not always possible, feasible or practical, which is why pseudonymization or data masking approaches will come in handy.

MORE TO READ:

Posted in .net, c#, General .NET | Tagged , , , , | 2 Comments

C# Mask email address for GDPR reasons

UPDATE 2018-08-10: See this post SHA256 hashing email addresses for GDPR reasons for an even better masking approcah. Thanks to Inspector Cluedget for the tip.

This is a C# extension method that will mask your email address following this pattern:

  • If it’s not an email, the entire string will be masked (“this string” => “***********”)
  • If the first part of the email is shorter than 4 characters, the entire email will be masked (me@somewhere.com => *@*.*)
  • All other emails are masked leaving only the first and last characters of the name and domain (somebody@somewhere.com => s******y@s*******e.com)

THE EXTENSION METHOD:

using System;
using System.Text.RegularExpressions;

namespace MyNamespace
{
  public static class EmailMasker
  {
    private static string _PATTERN = @"(?<=[\w]{1})[\w-\._\+%\\]*(?=[\w]{1}@)|(?<=@[\w]{1})[\w-_\+%]*(?=\.)";

    public static string MaskEmail(this string s)
    {
      if (!s.Contains("@"))
        return new String('*', s.Length);
      if (s.Split('@')[0].Length < 4) 
        return @"*@*.*"; 
      return Regex.Replace(s, _PATTERN, m => new string('*', m.Length));
    }
  }
}

USAGE:

using MyNamespace;

public void TestMethod()
{
  string email = "someperson@somedomain.com";
  string maskedEmail = email.MaskEmail();
  // result: s********n@s********n.com
}

WHY?

With the new GDPR rules you must be very careful when storing emails or other personal information anywhere, including your log files. And you should never give out a log file containing email addresses to a third party, even when this third party is “just helping you with a totally unrelated code bug elsewhere”.

There are many approaches to ensure GDPR compliance. The best way is to remove any personal data from any log file. This is not always possible, feasible or practical, which is why pseudonymization or data masking approaches will come in handy.

MORE TO READ:

 

Posted in .net, c#, General .NET | Tagged , , , | 3 Comments

Sitecore Display Name not Shown

My display names went missing from Sitecore. But only in my development environment, not the test or production environment.

Some googling lead me to this article from Stackexchange, but my database were in good condition.

It turns out, that even with 15 years of Sitecore experience, I did not know about this feature:

Click the burger menu in the Desktop and select “Application options”:

Application Options

Application Options

In the “View” tab, select “Display name (language-specific name)“, and the display names are visible again:

Display Name

Display Name

How on earth the setting jumped to “item key”, I simply don’t know.

MORE TO READ:

Posted in Sitecore 7, Sitecore 8, Sitecore 9 | Tagged , | Leave a comment

Sitecore and WebApi

So you have some legacy WebApi code that needs to run in your Sitecore solution? Or are just just a WebApi expert and need to use your favorite tool in the toolbox? Fear not, WebApi will run fine in your Sitecore solution.

You don’t need to use the native Sitecore 8.2 support for WebApi, you can use your own routes as well, and implement your nasty controller selectors, formatters and message handlers.

The API routes can be registered as a processor in the /sitecore/pipelines/initialize pipeline:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <sitecore>
    <pipelines>
      <initialize>
        <processor type="MyProject.RegisterApiRoutes, MyDll" />
      </initialize>
    </pipelines>
  </sitecore>
</configuration>

Please be aware, that Sitecore have taken the /api/sitecore and the /api/rest/ routes for it’s own code already, so use another route and you will avoid clashes with the Sitecore API.

This is my sample route registering, using the /myapi/ route instead of /api/:

using System.Web.Http;
using Newtonsoft.Json;
using Sitecore.Pipelines;

namespace MyProject
{
  public class RegisterApiRoutes
  {
    public void Process(PipelineArgs args)
    {
      HttpConfiguration config = GlobalConfiguration.Configuration;

      SetRoutes(config);
      SetSerializerSettings(config);
    }

    private void SetRoutes(HttpConfiguration config)
    {
      config.routes.MapHttpRoute("Features", "myapi/features", new { action = "Get", controller = "Feature" });
      config.routes.MapHttpRoute("Default route", "myapi/{controller}", new { action = "Get" });
    }

    private void SetSerializerSettings(HttpConfiguration config)
    {
      JsonSerializerSettings settings = new JsonSerializerSettings { ContractResolver = new DefaultContractResolver() };
      config.Formatters.JsonFormatter.SerializerSettings = settings;
      config.Formatters.Remove(config.Formatters.XmlFormatter);
      config.EnsureInitialized();
    }
  }
}

And I can implement my “Features” controller:

using System.Collections.Generic;
using System.Web.Http;

namespace Myproject
{
  public class FeatureController : ApiController
  {
    public dynamic Get()
    {
      return "hello world";
    }
  }
}

MORE TO READ:

 

Posted in .net, c#, General .NET, Sitecore 7, Sitecore 8, Sitecore 9 | Tagged , | Leave a comment

Creating dynamic arrays and lists using Dynamic and ExpandoObject in C#

In this previous post, C# Using Newtonsoft and dynamic ExpandoObject to convert one Json to another, I described how you can use the dynamic keyword and the ExpandoObject class to quickly transform JSON without the need for any concrete implementations of either the source or destination JSON.

This is an example of a dynamic list where you do not know the number of objects in the output array:

dynamic output = new List<dynamic>();

dynamic row = new ExpandoObject();
row.NAME = "My name";
row.Age = "42";
output.Add(row);

USAGE IN REAL LIFE:

Imagine you need to convert the following JSON by taking only those rows where the age is above 18:

{
	"attributes": [{
			"name": "Arthur Dent",
			"age": 42,
		},
		{	"name": "Ford Prefect",
			"age": 1088,
		},
		{	"name": "Zaphod Beeblebrox",
			"age": 17,
		}]
}

The code to transform the JSON would look something like this:

// Convert input JSON to a dynamic object
dynamic input = JsonConvert.DeserializeObject(myQueueItem);

// Create a list of dynamic object as output
dynamic output = new List<dynamic>();

foreach (var inputAttribute in input.attributes)
{
  if (inputAttribute.Age >= 18)
  {
    // Create a new dynamic ExpandoObject
    dynamic row = new ExpandoObject();
	row.name = inputAttribute.name;
	row.age = inputAttribute.age;
	// Add the object to the dynamic output list
	output.Add(row);
  }
}

// Finally serialize the output array
string outputJson = JsonConvert.SerializeObject(output);

The output is this:

[
  {  "name": "Arthur Dent",
	 "age": 42,
  }, 
  {	 "name": "Ford Prefect",
	 "age": 1088,
  }
]

MORE TO READ:

Posted in .net, c#, General .NET | Tagged , , , | Leave a comment

Sitecore open internal links in new window

Frequent users of Sitecore have already noticed that the “Insert Sitecore Link” dialog does not have a target selector:

Insert Internal Link

Insert Internal Link

Yes it’s true, if you wish to open an internal link in a new windows, it’s a 2 step process. First you add the internal link. Then you select the link and click the “Hyperlink Manager“. From here you can choose the target of the link:

Hyperlink Manager

Hyperlink Manager

MORE TO READ: 

Posted in Sitecore 5, Sitecore 6, Sitecore 7, Sitecore 8, Sitecore 9 | Tagged , , | Leave a comment

Sitecore install local SSL certificate for shared xConnect SOLR server

In Sitecore 9, the SOLR connection is secure by default. The effect is that if your development environment includes a shared SOLR server, your local IIS requires a SSL certificate issued for that server, even when your local site does not run HTTPS.

This makes installing a local dev environment a little but more complicated, which is why my colleague Kristian Gansted made this guide for me:

STEP 1: GET THE SSL CERTIFICATE FOR THE SOLR SSL SERVER

DevOps should provide you with the appropriate .pfx file.
Double click the file and follow the guide:

STEP 2: USE THE CERTIFICATE IMPORT WIZARD TO INSTALL THE CERTIFICATE

Select the Local Machine and click next:

Certificate Import Wizard

Certificate Import Wizard – Select the Local Machine

On the “File to Import“, the file name is already chosen so just click next, and go the “Private key protection“. Do not select a password, just click “Next”:

No Password

Do not select a password. Just click Next

In the Certificate Store, click “Browse…” and select the “Personal” store:

Certificate Store

Select “Personal” store

Click “Next” and click “Finish”. The certificate is now installed.

The import was successful

The import was successful

STEP 3: ALLOW AppPool ACCESS TO THE CERTIFICATE

Find the “Manage computer certificates” control panel:

Manage Computer Certificates

Manage Computer Certificates

Find the certificate under the “Personal” certificates, right click and find the “Manage Private Keys…” under “All Tasks“:

Certificates

Find the certificate, right click and find Manage Private Keys under “All tasks”

Press “Add” (1) to add a new user.
Press “Locations” (2) and select the machine to search in the correct location.

Select the correct location

Select the correct location

Then type “IIS APPPOOL/[name of IIS site]”:

Select User

Select IIS APPPOOL\[name of iis site]

Give the user full control.

Your IIS site is now ready to access the SOLR server.

MORE TO READ:

Posted in Sitecore 9 | Tagged , , , | Leave a comment

Azure Functions – How to retry messages in the poison queue

When working with a scenario where your Microsoft Azure Function reads data from a queue, your azure functions is automatically triggered when an entry is added to the queue you wish to read from.

The SDK will call your function 5 times, and the message is only removed from the trigger queue if:

  • The function was successful
  • The function fails 5 times

On the 5th fail, the message is moved to the poison queue, a separate queue named [queuename]-poison.

Queues and poison queues

Queues and poison queues

HOW TO RETRY THE POISON QUEUE:

Microsoft have built in methods for manual and automatically poison message handling, but there is no description of how to just retry the messages. In many situations, the problem causing your issue is fixed elsewhere, and all you need to do is retry the messages.

The solution is easier that I thought: The poison queue is just another queue, so all you need to do is to point the Azure Function to the poison queue, and the messages will be executed:

Read from Poison Queue

Read from Poison Queue

MORE TO READ:

 

Posted in c#, Microsoft Azure | Tagged , , | 2 Comments

Sitecore – what is the hash property in the image query string?

Have you also wondered why Sitecore adds a “hash=” property to the image query string?

https://yourwebsite.com/-/media/image.jpg?w=200&hash=A1FFA19B634EDF53A3AB3B757887E671F1C452A0

The hash key will protect your images from being scaled by others than your own server. The image above will only render if the hash key matches the width parameter:

The media request protection feature restricts media URLs that contain dynamic image-scaling parameters, so that only server-generated requests are processed. This ensures that the server only spends resources and disk space on valid image-scaling requests.

Sitecore, Protect media requests

This protects your server from using resources scaling images, if anyone tries to get an image from your server in another size. If the hash doesn’t match, the image is not scaled.

The feature can be disabled. In App_config/Include/Sitecore.Media.RequestProtection.config, Set Media.RequestProtection.Enabled to false:

<setting name="Media.RequestProtection.Enabled" value="false" />

MORE TO READ:

Posted in Sitecore 7, Sitecore 8, Sitecore 9 | Tagged , , | Leave a comment