(Skip the backstory to the technical implementation if you prefer technical stuff over the story)
Backstory
Earlier, I talked about using Modelsbuilder partial classes to enable Language Fallback on all variant properties, so your View Designers would have an easier time of using fallback without even realizing it.The reason I want this is:
I want (Razor) View Designers to be able to use
Model.Title
and not
Model.Value<string>("title", fallback: Fallback.ToLanguage)
I want them to
- not need to know HOW to get fallback on a poperty
- not need to know WHEN to use it (when a property is variant)
- not have an excuse to FORGET to use it
I wanted to find a better solution. I wanted Modelsbuilder to generate the .Value() method using Language Fallback by default.
I went as far as implementing it and making a Pull Request for ModelsBuilder, based on an AppSetting to enable this behaviour.
The PR was basically refused and a long discussion ensued wether or not what I wanted had merit and my solution was the correct approach.
Until one day, Ronald Barendse commented (paraphrased) "Why don't you just override the default Umbraco behaviour?"
My eyes opened and I went to work (and completed it unexpectedly fast).
Implementation
The default behaviour resides in the PublishedValueFallback class. To enable a solution just for this situation, they made the TryGetValue method virtual, so you can override it with whatever you need.using System.Linq;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.Services;
using Umbraco.Web.Models.PublishedContent;
namespace Dpw.Eworld2.Foundation.Umbraco.PublishedContent
{
public class CustomPublishedValueFallback : PublishedValueFallback
{
public CustomPublishedValueFallback(ServiceContext serviceContext, IVariationContextAccessor variationContextAccessor)
: base(serviceContext, variationContextAccessor)
{
}
public override bool TryGetValue<T>(IPublishedContent content, string alias, string culture, string segment, Fallback fallback, T defaultValue, out T value, out IPublishedProperty noValueProperty)
{
//When no fallback, use ToLanguage by default
if (!fallback.Any(f => f == Fallback.DefaultValue || f == Fallback.Language || f == Fallback.Ancestors))
{
fallback = Fallback.ToLanguage;
}
return base.TryGetValue(content, alias, culture, segment, fallback, defaultValue, out value, out noValueProperty);
}
}
}
Bascially, what I do is : when no fallback of any sort is requested, I put fallback to Language Fallback. Nothing else needs to change.
To enable this custom class instead of the default one, you register it in your Startup class as follows:
composition.RegisterUnique<IPublishedValueFallback, CustomPublishedValueFallback>();
I was then able to toss my PR, my custom built ModelsBuilder-version, all remaining partial classes and never need to even think about which property will be Variant.