API changes in Sitefinity CMS 7.0
Libraries
Upon upgrade to Sitefinity CMS 7.0, in the Libraries configuration screen, the default upload mode is now Html5. To switch mode between HTML5 and Silverlight media player, a new configuration option is introduced for configuring Libraries - the MediaPlayerMode. The default value of the option for new projects is Html5. For upgraded projects, the default value is Silverlight.
When you switch from MediaPlayerMode to Silverlight, the default configuration value for
AllowedExensionsSettings for videos is .wmv.
When you switch from MediaPlayerMode to Html5, the default configuration values for
AllowedExensionsSettings for videos is .MP4, .OGV, .WebM.
Third party libraries upgrades
- Kendo Controls Upgraded to 2014.1.321
- RadControls Upgraded to Q1 2014 SP1, version 2014.1.403
- Open Access Upgraded to Q1 2014 SP1 version 2014.1.403
- Service Stack Upgraded to
- Azure SDK upgrade to 2.2
Content modules API
The protected internal method GetAllAncestors is now removed from the Telerik.Sitefinity.Modules.ContentServiceBase class because its implementations in the inheriting services are returning the descendants of the specified parent. It is replaced by a protected method named GetDescendants.
The public method GetAncestorItems is removed from the Telerik.Sitefinity.Modules.LibrariesManager class because it was returning the descendants of the selected parents. It is replaced by a public method named GetDescendants.
Publishing system
The GetPropertyValue extension methods from the Telerik.Sitefinity.Publishing namespace are moved to a new ObjectPropertyExtensions class. Since extension methods are rarely called using class name and the namespace is kept, this is not expected to affect much code, if any.
Related Media API
Media fields are now replaced with the Related Media and Related Data fields. For backward compatibility, the old Media fields and API are left unchanged and will continue to work in the exactly same way. Therefore, if you have Media fields in any content type they will be active and will continue to work, they will not be changed with Related media fields. The only difference after upgrade to Sitefinity CMS 7.0 is be that you cannot add a Media field from the UI anymore. In addition, a dynamic module with old Media fields can be imported and activated and will continue to work properly.
Old Media field
- The GetValue and SetValue of the property descriptor (for the Media field) work with the content links and return content links.
- Media fields use a middle table implemented for the many to many relation between the fields and the media contents.
- Media fields are available in the dynamic modules.
New Related Media and Related Data fields
- The Related Media and Related Data fields are implemented to work only with the content links table, they do not use a middle table.
- There are three new properties added to the content links, stored in the database that marks if this particular content link is available for Temp, Master, and Live versions of the related item:
- available_for_temp
- available_for_live
- available_for_master
- The GetValue of the property descriptor now returns the actual items (not the content links). GetValue also applies a filter for the Live items requested from the frontend and in this case returns only the Live and Visible items.
- The Related Media and Related Data fields are available for custom fields of static modules (for example, Events, Blogs, Blog posts, List items, News, Pages), of dynamic modules, and Products.
Implementation changes
Implementation changes affect media content:
- Backend: Media fields like ImageField, AssetsField, MultiImageField, ProductDocumentsAndFilesField, and so on now work with SingleMediaContentItemDialog selector dialog instead of the EditorContentManagerDialog. The old dialog EditorContentManagerDialog is left unchanged for backward compatibility.
If you have customized the media fields listed above and are using the old EditorContentManagerDialog dialog, you may need to refactor your customizations. - Frontend: Image, Video, and Document widgets have new designers and designer views that also use the SingleMediaContentItemDialog selector dialog. Old designers and designer views are left unchanged for backward compatibility.
Therefore, if you have custom widgets that use the old designers you will not encounter any issues. - Content block now works with SingleMediaContentItemDialog selector dialog instead of the EditorContentManagerDialog.
Pages API
Changes in the Pages API can cause compilation errors and unexpected behavior. Samples are provided for what alternative code to use in place of the removed and obsolete methods and properties. The most widely-used scenario that could be affected is the multilingual split pages. That is, split pages are pages which have different layout and widgets. For example, the English version of one page has different widgets or layout compared to the French or Chinese. As a result, the page internal structure is improved. There is a more well-defined separation between page metadata (PageNode) and page presentation – (PageData). The metadata information which was previously located in PageData is now located in PageNode.
There is only one node containing the metadata and the page data items
(one item per language). This improvement removes the limitations of the page tree structure. Therefore,
it is now possible to have split and synchronized pages in all levels
of the page tree. Previously, only split pages could be created under a
split page.
An upgrade script runs upon first start of Sitefinity CMS 7.0 that copies specific data and deletes other data to comply with the API change.
PageNode – PageData reference
PageData now has a NavigationNode property that holds the reference to the page metadata (located in the PageNode). Previously, the PageNode had a Page property (of type PageData that is now obsolete). The main impact of this change is on Multilingual Split pages. You now get the PagaData of the PageNode in a different way.
Following is a description what code you need to change.
There are several cases when working with PageNode and PageData items that should be changed. The most common cases are searching for a PageNode based on some filter. Depending on the filter type, you might need to change the query (see code samples below). In other cases, you need to read or write some page information from or to the PageNode or PageData.
For properties that are migrated from PageData to PageNode there are two options:
- Properties used to read or write the value: the PageNode’s property value is returned internally and the PageNode’s value is set, respectively.
- Properties are part of LINQ expressions: an exception is thrown as this property is not mapped to thedatabase column anymore.
Samples below describe the different groups of changes that you need to implement.
Sample 1: Search for a PageNode based on properties moved from PageData to PageNode.
Stefinity 6.3 and older:
var nodesByTitle = PageManager.GetManager().GetPageNodes().Where(p => p.Page.Title ==
"home"
);
Sitefinity CMS 7.0 - the redundant usage of Page (PageData) is removed:
var nodesByTitle = PageManager.GetManager().GetPageNodes().Where(p => p.Title ==
"home"
);
Sample 2: Search for PageNode based on PageData properties that are not moved.
Sitefinity CMS 6.3 and older:
var nodesModifiedInLastDay = PageManager.GetManager().GetPageNodes().Where(p => p.Page.LastModified > DateTime.UtcNow.AddDays(-1));
Sitefinity CMS 7.0 - start from PageData items:
var nodesModifiedInLastDay = PageManager.GetManager().GetPageDataList().Where(pd => pd.LastModified > DateTime.UtcNow.AddDays(-1)).Select(pd => pd.NavigationNode).Distinct();
Sample 3: Get PageData for a specific node.
Sitefinity CMS 6.3 and older:
var nodeId = Guid.Parse(
"A4F6BAD9-B65D-6BD7-821E-FF00005B5385"
);
var pageData = PageManager.GetManager().GetPageNode(nodeId).Page;
Sitefinity CMS 7.0 - use the GetPageData() method of the PageNode (with optional culture parameter that is used for split pages for a given culture):
var pageData = PageManager.GetManager().GetPageNode(nodeId).GetPageData();
Content - inheritance removed from PageData
As of Sitefinity CMS 7.0, the PageData object stops to inherit Content. However, some interfaces are still inherited from PageData directly. The list of these inherited interfaces is:
- IVersionSerializable
- IExtensibleDataObject
- IOwnership
- IDynamicFieldsContainer
- IScheduleable
- IContent
Properties of PageData
Properties of PageData related to the page metadata are moved to PageNode. The PageData properties are marked as obsolete and they internally fallback to PageNode. Such properties are:
- Crawlable
- RequireSsl
- LocalizationStrategy
- IsBackendPage
- UrlName
- IsSplitPage
- IsBackend
Removed properties:
- Properties that are related to the language information of linked nodes are removed: PageLanguageLink
- With the content inheritance removed there are some properties that are now missing from PageData. Such properties are: AllowComments, AllowTrackBacks, ApproveComments, AvailableLanguages, Comments, CommentsConfigPath, ContentState, DefaultPageId, DraftCulture, EmailAuthor, Organizer, OriginalContentId, PostRights.
Workflow API
In previous versions, the content workflow API implied using a property ApprovalTrackingRecordMap on all workflow enabled items, which gave access to the workflow publishing history. This property is made obsolete in Sitefinity CMS 7.0 and is replaced with an extension method. An upgrade script runs upon first start of Sitefinity CMS 7.0 that drops several tables that are no longer needed.
The projects that will be most affected as a breaking change are any Custom modules with Open Access data persistence with enabled approval workflow - we are providing instructions how to upgrade those in the document referred above. For the stock Sitefinity CMS modules and the modules implemented with the Module builder we are performing automatic upgrade.
Following is a list with the workflow API changes:
- A new DeletePageActivity workflow activity is introduced in the PagesApprovalWorkflow.xamlx file. The new activity replaces the code activity for deleting a page. If you have a custom page workflows, we recommend that you use the new activity for deleting a page since the DeletePageActivity activity also checks for content relating to a page before deleting the page.
- The ApprovalWorkflowRecordMap class is no longer mapped to the database. The ApprovalWorkflowRecordMap property of all content items (including dynamic ones) is no longer used and is marked as Obsolete.
- The Parents property of the ApprovalWorkflowRecord class is no longer used and is marked as Obsolete.
- An extension method of the IWorkflowItem interface is provided in the Telerik.Sitefinity namespace to get the approval records associated with an item. For Lifecycle items, the approval tracking record is associated with the master item.
Events API
The event items now introduce a new property TimeZoneId that helps to accurately calculate recurring events. Upon upgrading to Sitefinity CMS 7.0, all events will have their TimeZoneId property set to the default timezone set by the Sitefinity CMS configuration. The upgrade script corrects and prevents potential errors in related to previously created recurring events.
There are also changes related to the Calendar widget.
Recurring events
The Event object contains information about the timezone in which the event was created. There a few new properties in that object:
- EventStartUtcOffset
- EventEndUtcOffset
- TimeZoneId
The EventStart and EventEnd properties are now in UTC.
Other changes:
- IRecurrenceDescriptor, RecurrenceRule and all derived types from the Event object now support TimeZoneId.
- The IRecurrenceDescriptor Occurences and IRecurrenceDescriptor Exceptions are now retrieved in UTC related to the time zone.
- IRecurrenceDescriptor EventStart and IRecurrenceDescriptor EventEnd are now with Unspecified Kind datetime objects, so there is no conversion for them.
Be aware that some custom functionality that is related to the Events module needs to be rewritten. All custom widgets created with scaffold info data need to be modified to use the ToSitefinityUITime() method. Here is an example for the EventEnd scaffoldinfo:
[ScaffoldInfo(
"<sitefinity:TextField runat=\"server\" DisplayMode=\"Read\" Value='<%# ((DateTime)Eval(\"EventEnd\")).ToSitefinityUITime() %>' />"
)]
The RecurrenceExpression property of the Event now stores the EventStart and EventEnd dates with values related to the time zone.
Calendar widget
The Calendar widget has some changes related to the daylight saving time:
- IRadSchedulerService.cs: the GetAppointments() and UpdateAppointment() methods used to return IEnumerable<AppointmentData>. As of Sitefinity CMS 7.0, these methods return SitefinitySchedulerOperationResult.
- RadSchedulerService.cs: the GetAppointments() and UpdateAppointments() methods used to return IEnumerable<AppointmentData>. As of Sitefinity CMS 7.0, these methods return SitefinitySchedulerOperationResult.
- The SitefinitySchedulerOperationResult is a new class that inherits from Telerik.Web.UI.SchedulerOperationResult<AppointmentData> and has three additional properties – StartDST, EndDST, and DaylightDelta.
Ecommerce module
The CartOrder widget now has a property UserId that holds the ID of the user that was logged in when the cart was created. Thus, in case users switch, they are not able reuse old shopping carts. As a result, the configuration property KeepShoppingCartPerUser has a default value true.
Custom static modules
When upgrading custom static modules, you must remove from the
FluentMapping
of the content item the mapping association between the content item and the
ApprovalTrackingRecordMap
object. Remove the following code line:
ItemMapping.HasAssociation<Telerik.Sitefinity.Workflow.Model.Tracking.ApprovalTrackingRecordMap>(p => p.ApprovalTrackingRecordMap);
NOTE: If you do not delete the code above, all approval records are lost and information such as the Note text when rejecting a content item will not be available anymore.
The purpose of this step is to redirect the old approval records to point to the master version of the content item. If there are any OpenAccessProviders present, they must implement the IOpenAccessUpgradableProvider interface. When implementing an upgrade for the OpenAccess provider, take into account the following:
- The table name of the content item, for example custom_products.
- The ID of the foreign key.
Usually, if you do not have any other relations to other persistent types, the ID is id or id2, for example.
Following is a sample implementation for the Products Sample module:
[ContentProviderDecorator(
typeof
(OpenAccessContentDecorator))]
public
class
OpenAccessProvider : ProductsDataProvider, IOpenAccessDataProvider, IOpenAccessUpgradableProvider
{
public
virtual
int
CurrentSchemaVersionNumber
{
get
{
return
this
.GetAssemblyBuildNumber();
}
}
public
virtual
void
OnUpgrading(UpgradingContext context,
int
upgradingFromSchemaVersionNumber)
{
if
(upgradingFromSchemaVersionNumber < 5100)
//5100 is the version number for sitefinity 7.0
{
var message =
"{0} : Upgrade to {1}. Update approval records."
.Arrange(
this
.GetType().Name,
"5100"
);
try
{
UpdateRecords(context, tableName, primaryKeyColumn);
DropColumn(context,
"custom_products"
, "id”);
Log.Write(
string
.Format(
"PASSED : {0}"
, message), ConfigurationPolicy.UpgradeTrace);
}
catch
(Exception ex)
{
Log.Write(
string
.Format(
"FAILED: {0} - {1}"
, message, ex.Message), ConfigurationPolicy.UpgradeTrace);
if
(Exceptions.HandleException(ex, ExceptionPolicyName.IgnoreExceptions))
throw
;
}
}
}
private
static
void
UpdateRecords(OpenAccessContext context,
string
tableName,
string
primaryKeyColumn)
{
var sql = @"update sf_approval_tracking_record
set
sf_approval_tracking_record.workflow_item_id = {0}.content_id
from {0}
join sf_pprvl_trckng_rcrd_mp_sf_ppr
on {0}.{1} = sf_pprvl_trckng_rcrd_mp_sf_ppr.id
join sf_approval_tracking_record
on sf_pprvl_trckng_rcrd_mp_sf_ppr.id2 = sf_approval_tracking_record.id
where {0}.status = 0".Arrange(tableName, primaryKeyColumn);
context.ExecuteNonQuery(sql);
}
private
static
void
DropColumn(OpenAccessContext context,
string
tableName,
string
columnName)
{
var sql =
"DropColumn ALTER TABLE {0} DROP COLUMN {1}"
.Arrange(tableName, columnName);
context.ExecuteNonQuery(sql);
}
public
virtual
void
OnUpgraded(UpgradingContext context,
int
upgradedFromSchemaVersionNumber)
{
}
Content modules API
Telerik.Sitefinity.Modules.ContentServiceBase class
In older Sitefinity CMS versions, the GetAllAncestors method was a protected method in the ContentServiceBase class. The change affects only inheritors of the latter class in case they used to call or override the GetAllAncestors method.
Old code that no longer compiles:
public
class
CustomAlbumService : ContentServiceBase<Album, AlbumViewModel, LibrariesManager>
{
...
public
IQueryable<Album> GetDescendants(Guid parentGuid,
string
providerName)
{
return
this
.GetAllAncestors(parentGuid, providerName);
}
...
}
Code introducing the new method:
public
class
CustomAlbumService : ContentServiceBase<Album, AlbumViewModel, LibrariesManager>
{
...
public
IQueryable<Album> GetDescendants(Guid parentGuid,
string
providerName)
{
return
this
.GetDescendants(parentGuid, providerName);
}
...
}
Telerik.Sitefinity.Modules.LibrariesManager class
In older Sitefinity CMS versions, the GetAncestorItems method was a public method in LibrariesManager class. Only code that queries media items may be affected by the change.
Old code that no longer complies:
var manager = LibrariesManager.GetManager();
var library = manager.GetLibraries().First();
var descendants = manager.GetAncestorItems(library);
Code introducing the new method:
var manager = LibrariesManager.GetManager();
var library = manager.GetLibraries().First();
var descendants = manager.GetDescendants(library);