Umbraco Site - Global Properties/Config for frontend and backend
Hi guys,
I'd like to have your inputs/best-practices suggestions regarding defining global properties in Umbraco that could be edited by the content editors/admins, in a way that could be easily and elegantly retrieved either on the frontend or backend, in a multilingual website.
Giving a concrete example:
Imagine that a have a property in each site root that links to the
URL of a login page, so in the Language A root I link to
http:/domain.com/login-A and in the Language B root I link to
http://domain.com/login-B
For the frontend what I want to do is to be able to retrieve this link property in a partialview or macro (in a template page I can get the property using @CurrentPage.Root.property)
For the backend what I want to is also to retrieve that same root property to send in an email for example
One thing I was thinking of was using a helper and server cache that is initialised in app startup and gets updated when the root doc type is published....but there's also the problem of having a multilingual website...
What are your suggestions/advices?
I do pretty much as you describe. That is, I have that sort of data stored on a single node (not necessarily the root/homepage node), and to make sure it's fast I store the data in a server-side cache.
And to ensure what's stored in that cache is up to date, I use one of the invalidators (e.g., so the cache will be refreshed after the page storing the data gets published): https://github.com/rhythmagency/rhythm.caching.umbraco
While not shown in the README, I handle multilingual websites by using a key parameter to the 'Get` method. That is, I ensure the current language is part of the key used to isolate variables. Another important thing to include in the key is whether or not the site is currently in preview mode (so preview data doesn't pollute the live site).
Our implementation is close to Nicholas's as well, except that the configuration "tree" of nodes is stored as a separate node in the root, called something like "Global Configuration", then we have a series of child nodes for the various types of config.
In the site's root node, I have a reference to the configuration to use, so in the pages of the site, I can get the root node of the site, then get the configuration.
This allows me the most flexibility, in that I can host multiple sites with the same or different configuration.
@Nicholas - do you have an example of how to use the Rhythm.Caching.Umbraco framework? I've looked into the source code but I'm wondering if using the caching.umbraco is sufficient or if I need to use the caching.core itself :)
@John - but then how do you deal with using that configuration in a partial view and/or backend side? :)
In any partial views we typically include either a form field for postback/ajax calls that includes the document ID of the main node bein rendered, or in cases where we call embedded partials, we simple pass the document view object, node id into the partial and access the root node of the current document being rendered
Rhythm.Caching.Core can be used with any project. Rhythm.Caching.Umbraco adds some Umbraco-specific stuff (e.g., an invalidator to clear the cache when a particular page or page with a particular document type is published).
So you want both.
Here's an example that I'm working on this very moment:
/// <summary>
/// Get the coordinate of a location.
/// </summary>
/// <param name="address">
/// The location address information.
/// </param>
/// <param name="locationId">
/// The ID of the Umbraco content node.
/// </param>
/// <returns>
/// The coordinate.
/// </returns>
public static GeoCoordinate GetCoordinate(LocationAddress address, int locationId)
{
// Variables.
var duration = CacheUtility.LongDuration;
var keys = CacheUtility.GetCacheKeys(CacheKeyKinds.Domain | CacheKeyKinds.Preview);
// Get the coordinates from the cache.
return CoordinateCache.Get(locationId, id =>
{
// First, attempt to get the coordinate from the location node.
var latitude = NumberParsing.AttemptParseDouble(address.Latitude);
var longitude = NumberParsing.AttemptParseDouble(address.Longitude);
if (latitude.HasValue && longitude.HasValue)
{
return new GeoCoordinate(latitude.Value, longitude.Value);
}
// Fallback to asking Google for the coordinate.
var coordinate = GeographyHelper.GeocodeAddress(address.AddressStreet, null,
address.City, address.State, "United States", address.ZipCode);
// Pause a moment to avoid geocoding too frequently (may run into Google rate limit).
// See: https://developers.google.com/maps/documentation/geocoding/usage-limits
Thread.Sleep(100);
// Return the geocoded coordinate.
return coordinate;
}, duration, keys: keys);
}
The CacheUtility is something specific to a project I'm working on (i.e., you won't find it in these libraries). This is how I define some static variables in that class:
/// <summary>
/// A cache of coordinates.
/// </summary>
private static InstanceByKeyCache<GeoCoordinate, int> CoordinateCache { get; set; }
/// <summary>
/// Invalidates the cache of coordinates.
/// </summary>
private static InvalidatorByPage<GeoCoordinate> CoordinateCacheInvalidator { get; set; }
And this is how I initialize them in the static constructor for that class:
CoordinateCache = new InstanceByKeyCache<GeoCoordinate, int>();
CoordinateCacheInvalidator = new InvalidatorByPage<GeoCoordinate>(CoordinateCache);
I'm using namespaces from both libraries:
using Rhythm.Caching.Core.Caches;
using Rhythm.Caching.Umbraco.Invalidators;
Not exactly the same as the settings scenario you are talking about, but hopefully this real world example helps to conceptualize it a bit.
Umbraco Site - Global Properties/Config for frontend and backend
Hi guys,
I'd like to have your inputs/best-practices suggestions regarding defining global properties in Umbraco that could be edited by the content editors/admins, in a way that could be easily and elegantly retrieved either on the frontend or backend, in a multilingual website.
Giving a concrete example:
For the frontend what I want to do is to be able to retrieve this link property in a partialview or macro (in a template page I can get the property using @CurrentPage.Root.property)
For the backend what I want to is also to retrieve that same root property to send in an email for example
One thing I was thinking of was using a helper and server cache that is initialised in app startup and gets updated when the root doc type is published....but there's also the problem of having a multilingual website... What are your suggestions/advices?
Thank you very much guys!
I do pretty much as you describe. That is, I have that sort of data stored on a single node (not necessarily the root/homepage node), and to make sure it's fast I store the data in a server-side cache.
Specifically, I use what I call an InstanceCache: https://github.com/rhythmagency/rhythm.caching.core
And to ensure what's stored in that cache is up to date, I use one of the invalidators (e.g., so the cache will be refreshed after the page storing the data gets published): https://github.com/rhythmagency/rhythm.caching.umbraco
While not shown in the README, I handle multilingual websites by using a
key
parameter to the 'Get` method. That is, I ensure the current language is part of the key used to isolate variables. Another important thing to include in the key is whether or not the site is currently in preview mode (so preview data doesn't pollute the live site).Our implementation is close to Nicholas's as well, except that the configuration "tree" of nodes is stored as a separate node in the root, called something like "Global Configuration", then we have a series of child nodes for the various types of config.
In the site's root node, I have a reference to the configuration to use, so in the pages of the site, I can get the root node of the site, then get the configuration.
This allows me the most flexibility, in that I can host multiple sites with the same or different configuration.
Thanks Nicholas and John for your answers.
@Nicholas - do you have an example of how to use the Rhythm.Caching.Umbraco framework? I've looked into the source code but I'm wondering if using the caching.umbraco is sufficient or if I need to use the caching.core itself :)
@John - but then how do you deal with using that configuration in a partial view and/or backend side? :)
Regards
In any partial views we typically include either a form field for postback/ajax calls that includes the document ID of the main node bein rendered, or in cases where we call embedded partials, we simple pass the document view object, node id into the partial and access the root node of the current document being rendered
Rhythm.Caching.Core
can be used with any project.Rhythm.Caching.Umbraco
adds some Umbraco-specific stuff (e.g., an invalidator to clear the cache when a particular page or page with a particular document type is published).So you want both.
Here's an example that I'm working on this very moment:
The
CacheUtility
is something specific to a project I'm working on (i.e., you won't find it in these libraries). This is how I define some static variables in that class:And this is how I initialize them in the static constructor for that class:
I'm using namespaces from both libraries:
Not exactly the same as the settings scenario you are talking about, but hopefully this real world example helps to conceptualize it a bit.
is working on a reply...