IDataUrlMapper
Map data references to URLs
Data URL mappers define the relation between URLs and data references. For example, these mappers enable such CMS Console features as previewing data while navigating the console tree.
To use data URL mappers, you should:
- Create a class implementing the
Composite.Core.Routing.IDataUrlMapper
interface.namespace Composite.Core.Routing { public interface IDataUrlMapper { IDataReference GetData(PageUrlData pageUrlData); PageUrlData GetPageUrlData(IDataReference instance); } }
- Register an instance with one of the following methods:
Composite.Core.Routing.DataUrls.RegisterGlobalDataUrlMapper(Type dataType, IDataUrlMapper dataUrlMapper)
Composite.Core.Routing.DataUrls.RegisterStaticDataUrlMapper(Guid pageId, Type dataType, IDataUrlMapper dataUrlMapper)
Composite.Core.Routing.DataUrls.RegisterDynamicDataUrlMapper(Guid pageId, Type dataType, IDataUrlMapper dataUrlMapper)
RegisterGlobalDataUrlMapper
: registers a data URL mapper for a given data typeRegisterStaticDataUrlMapper
: registers a data URL mapper for a given data type and for a specific pageRegisterDynamicDataUrlMapper
: similar toRegisterStaticDataUrlMapper
, registers a data URL mapper for a given data type and for a specific page but the instance will be cleared when the page is edited.
Both RegisterGlobalDataUrlMapper
and RegisterStaticDataUrlMapper
are to be called only once at the website startup while RegisterDynamicDataUrlMapper
is to be called during page rendering, allowing CMS Functions to both view the data and register a mapper, so the console could be "aware" of the relation.
(The RoutedData<T> functionality is implemented using RegisterDynamicDataUrlMapper
.)
While URLs for a data reference are getting built, the mappers are used in this order:
- The global mappers are used first.
- If a data item inherits
IPageRelatedData
(all the page data folder types do so), static mappers are then used to resolve the URL - If the URL has not been resolved yet, the system will render the page (if not rendered yet) to collect and use dynamically attached data URL mappers.
Using IDataUrlMapper
In the following example, you will enable previewing data of the dynamic global data type "Demo.News" on the page "News":
The Demo.News
type's fields:
- Id: Guid
- Title: String (64)
- Date: Date
- Content: String (1024), Widget: TextArea
(You can use the Demo.News package to automatically create this data type with some fictitious data.)
If you are using your own data type, change the code accordingly.
In this example, you will:
- Define a data URL mapper
- Create its instance and register it in a startup handler
- Create a CMS Function to display the data
Create corresponding classes (Steps 1 and 2) and copy the output DLL to /Bin
on your website.
Defining a data URL mapper
using Composite.Core.Routing; using Composite.Core.Types; using Composite.Data; using System; using System.Linq; namespace Composite.Demo { public class NewsDataMapper : IDataUrlMapper { private readonly Guid _pageId; private readonly Type _dataType; private readonly Type _keyType; public NewsDataMapper(Type dataType, Guid pageId) { _pageId = pageId; _dataType = dataType; _keyType = _dataType.GetKeyProperties().Single().PropertyType; } public IDataReference GetData(PageUrlData pageUrlData) { if (pageUrlData.PageId != _pageId) { return null; } string pathInfo = pageUrlData.PathInfo; if (string.IsNullOrEmpty(pathInfo) || pathInfo.Length == 1) { return null; } string[] parts = pathInfo.Split('/'); if (parts.Length != 2 || string.IsNullOrEmpty(parts[1])) { return null; } string keyString = parts[1]; object keyValue = ValueTypeConverter.Convert(keyString, _keyType); var data = keyValue != null ? DataFacade.TryGetDataByUniqueKey(_dataType, keyValue) : null; return data != null ? data.ToDataReference() : null; } public PageUrlData GetPageUrlData(IDataReference instance) { if (instance.ReferencedType != _dataType) { return null; } var page = PageManager.GetPageById(_pageId); if (page == null) { return null; } var key = instance.KeyValue; return new PageUrlData(page) { PathInfo = "/" + key }; } } }
Creating and registering an instance of the mapper
Note. In this example, a hard-coded ID of the page where the data will show is used.
using Composite.Core.Application; using Composite.Core.Routing; using Composite.Data; using System; using System.Linq; namespace Composite.Demo { [ApplicationStartup] public static class StartupHandler { // The ID of the page to show the data of the Demo.News type on - change accordingly static readonly Guid TargetPageId = new Guid("055a1076-099b-420c-a9cc-f591e0819782"); public static void OnBeforeInitialize() { } public static void OnInitialized() { // Finding a dynamic data type var dataType = DataFacade.GetAllInterfaces().FirstOrDefault(u => u.Name == "News"); // var dataType = typeof(....); if (dataType != null) { DataUrls.RegisterGlobalDataUrlMapper(dataType, new NewsDataMapper(dataType, TargetPageId)); } } } }
Creating and using a CMS Function to display the data
Create a Razor function:
@using Composite.Core.Routing @using Composite.Core.Routing.Pages @inherits RazorFunction @functions { public override string FunctionDescription { get { return "List news on a page."; } } string GetUrl(Demo.News data) { return PageUrls.BuildUrl(DataUrls.TryGetPageUrlData(data.ToDataReference())); } } @{ var dataReference = DataUrls.TryGetData(C1PageRoute.PageUrlData); Demo.News itemToShow = dataReference != null ? dataReference.Data as Demo.News : null; if (itemToShow != null) { C1PageRoute.RegisterPathInfoUsage(); } } <html xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://www.composite.net/ns/function/1.0"> <head> </head> <body> @if (itemToShow != null) { <h1> @itemToShow.Title </h1> <em> @itemToShow.Date </em> <p> @itemToShow.Content </p> <br /> <a href="@Data.SitemapNavigator.CurrentPageNode.Url"> Back to list</a> } else { <h1> List of news items: </h1> foreach (var item in Data.Get<Demo.News>()) { <div> <a href="@GetUrl(item)"> @item.Title </a> </div> } } </body> </html>
Now insert the function on the page you've specified when registering the mapper in the startup handler: "News" (Id: 055a1076-099b-420c-a9cc-f591e0819782
) in this example.
Examples of using the API
One can call the registered mappers by calling static methods:
DataUrls.TryGetData(PageUrlData pageUrlData)and
DataUrls.TryGetPageUrlData(IDataReference dataReference)Examples:
// IData ->URL: IData dataItem = ...; var pageUrlData = DataUrls.TryGetPageUrlData(newsItem.ToDataReference()); string url = pageUrlData != null ? PageUrls.BuildUrl(pageUrlData) : null;
// URL -> IData: string url = ...; var pageUrlData = PageUrls.ParseUrl(url); var dataReference = pageUrlData != null ? DataUrls.TryGetData(pageUrlData) : null; IData data = dataReference != null ? dataReference.Data : null;
Requirements:
C1 CMS version 5.0 or later