Glass Mapper and line breaks in multi-line fields in Sitecore

Search for a command to run...

No comments yet. Be the first to comment.
Polly is great library for easily configuring different kinds of policies around code execution, be it retry, circuit breaker, caching or lots of other things. It's probably most often used around HTTP requests. If you haven't heard about it you defi...

This is part 2 of my series on unit testing in .NET (C#) and will be about my conventions regarding naming unit tests, how to structure them and which parts to test. And lastly I will help you increase readability of assertions and potential error me...

I feel like unit testing is very important and very beneficial in a lot of ways. It helps with not breaking existing functionality and thereby also making you more confident in changing code without fear of breaking important stuff. Often it also mak...

I've been working with Swagger through NSwag a lot recently and also needed to get it to work when hidden behind a reverse proxy - i.e. another service forwarding a request to the service exposing the Swagger UI. Some of the issues I've had along the...

The other day I was writing a unit test to verify what was supposed to happen when a Task would throw an exception when awaited. It wasn't as straight forward as I first assumed, but I quickly found this Stack Overflow post that helped me: https://st...

If you are using Glass.Mapper and have multi-line fields in Sitecore that contains line breaks (which is sort of the reason for the multi-line field) you might have run into this “issue” (or at least unexpected behavior in my eyes) that Glass.Mapper doesn’t convert line breaks (\r\n) to <br> tags, although Sitecore outputs <br> tags if using the standard API.
Their reasoning is something along the lines of not wanting to manipulate the raw data as it might not always be used in an HTML-context where <br> tags would be the right choice. When rendering a multi-line field in HTML you need line breaks to be <br> tags, but if you use it in non-HTML contexts the <br> tags would be bad, so there are both pros and cons to their approach, but I would probably prefer it if it would default to <br> and an option to change it.
This was specifically a problem for our editors, who would insert line breaks through the Experience Editor and then they would not show up when publishing the page – leaving them confused.
There are actually two issues going on here – one in normal mode and one in edit mode (Experience Editor).
When Glass Mapper outputs the content of fields it does it differently depending on the page mode. When not in edit mode it just outputs the raw value for most fields except Link and Image types while in edit mode it runs the renderField pipeline (more about this at the bottom).
One solution to this issue is to create a custom data mappe for Glass, that extends the default mapper for string. (solution show further down)
I started to look into how Glass.Mapper handles rendering the different field types in the different situations. With a little help from Mike Edwards and the guys in the #glass channel on the Sitecore Slack channel, who pointed me in the right direction, I ended up making a custom data mapper – MultiLineSitecoreFieldStringMapper (extending the default SitecoreFieldStringMapper).
using System;
using System.Collections.Concurrent;
using Glass.Mapper.Sc;
using Glass.Mapper.Sc.Configuration;
using Glass.Mapper.Sc.DataMappers;
using Sitecore.Data.Fields;
namespace YourNamespace
{
public class MultiLineSitecoreFieldStringMapper : SitecoreFieldStringMapper
{
private static readonly ConcurrentDictionary<Guid, bool> IsMultiLineDictionary = new ConcurrentDictionary<Guid, bool>();
public override object GetField(Field field, SitecoreFieldConfiguration config,
SitecoreDataMappingContext context)
{
var value = (string) base.GetField(field, config, context);
var guid = field.ID.Guid;
if (IsMultiLineDictionary.ContainsKey(guid) && IsMultiLineDictionary[guid])
return FixMultiLineFieldLineBreaks(value);
var isMultiLine = field.TypeKey == "multi-line text";
IsMultiLineDictionary.TryAdd(guid, isMultiLine);
if (!isMultiLine)
return value;
return FixMultiLineFieldLineBreaks(value);
}
private static string FixMultiLineFieldLineBreaks(string value)
{
return value?.Replace("\r\n", "<br>");
}
}
}
It extends the default functionality from the default SitecoreFieldStringMapper and basically just replaces the \r\n with <br> if the field being rendered is a multi-line field.
To make Glass.Mapper use our custom data mapper we have to add it to the resolver’s DataMapperFactory. This is done in the GlassMapperScCustom class that is generated when you install the NuGet package. We add it first so that it is used instead of the existing mapper for string., like shown below (you could probably just remove the existing one instead as well).
public static class GlassMapperScCustom
{
public static IDependencyResolver CreateResolver(){
var config = new Glass.Mapper.Sc.Config();
var resolver = new DependencyResolver(config);
resolver.DataMapperFactory.Insert(0, () => new MultiLineSitecoreFieldStringMapper());
return resolver;
}
/* ... */
}
Multi-line fields with line breaks will now be rendered “as expected” – with line breaks.
There is a bug in recent versions of Sitecore – at least 8.2 and some versions of 8.1 – where the renderField pipeline doesn’t output line breaks as <br> by default. This means you can add line breaks to your multi-line field and they will be saved, but when refreshing the page they will appear to be gone.
When in edit mode Glass Mapper runs the renderField pipeline to get the value of a field, so our custom data mapper is not used in this situation.
This is the same way Sitecore does it if you use the default API, like this:
@Html.Sitecore().Field("Multi line field")
Sitecore is tracking this bug by reference number 95002 and you can read a bit more about it and how to fix it in my other post.