Disclaimer: This website requires Please enable JavaScript in your browser settings for the best experience.

HomeDev GuideRecipesAPI Reference
Dev GuideAPI ReferenceUser GuideLegal TermsGitHubNuGetDev CommunityOptimizely AcademySubmit a ticketLog In
Dev Guide

Discover the platform

Several common concepts and conventions apply throughout the Optimizely Community (formerly Social) API. An understanding of these strategies is helpful in discovering the tools available to you.

Services

The primary point of interaction with the Optimizely Community API is the service classes exposed by each platform's features. Each service implements an interface which conforms to the following naming convention: I{Feature-Name}Service. Examples include:

  • ICommentService
  • IRatingService
  • IGroupService

Suppose a platform feature is installed on an Optimizely Content Management System (CMS) site with the feature's site integration package. In that case, you can get an instance of a service from the inversion of control (IoC) container.

Example

var commentService = EPiServer.ServiceLocation.ServiceLocator.Current.GetInstance<ICommentService>();

If a platform feature is installed on a non-Optimizely CMS site, you can get an instance of a service from the default factory classes provided within the package.

Example

var factory = new EPiServer.Social.Moderation.Factories.DefaultWorkflowServiceFactory();
var workflowService = factory.Create();

Data models

You can find the data models consumed and returned by the Community API's services beneath the "core" namespace accompanying a particular platform feature. The convention for "core" namespaces is EPiServer.Social.{Feature-Name}.Core. For example:

  • EPiServer.Social.Comments.Core
  • EPiServer.Social.Ratings.Core

Exceptions

You can find exceptions thrown by the Community API's services beneath the Core namespace accompanying a particular platform feature. The convention for Core namespaces is: EPiServer.Social.{Feature-Name}.Core. For example:

  • EPiServer.Social.Comments.Core
  • EPiServer.Social.Ratings.Core

Additionally, you may find exception types, which are shared throughout the platform, in the EPiServer.Social.Common namespace.

Platform exceptions

The features of the Optimizely Community API share several exception types to communicate general platform error situations.

SocialAuthenticationException

A SocialAuthenticationException is thrown by Optimizely Community API service methods when a request is deemed unauthentic.

This error most commonly occurs when:

  • The application's configuration is missing one or more of its authentication settings.
  • The application's configuration contains inaccurate authentication settings.
  • The application's server time is inaccurate.

For information regarding configuration and authentication, see Get connected in Install Optimizely Community.

MaximumDataSizeExceededException

A MaximumDataSizeExceededException is thrown by methods of an Optimizely Community API service when a request exceeds the platform's size restrictions.

The platform accepts social content up to 10 kilobytes in size. This restriction applies to any given social entity, including the native properties of the platform's content models, optional extension data, and any overhead of those models.

For example, consider a simple comment containing an author, body, and parent reference. Consider that you also composed this comment with custom extension data. The content associated with each of those native comment properties and the extension data contribute to the total size of the request.

The platform does not explicitly restrict the amount of content associated with any individual property of a social content model. This lets you prioritize the content size that the application allows to native content models versus custom extension data.

📘

Note

The application should enforce limits on the amount of content that may be contributed, as applicable to its use cases. In doing so, it minimizes the likelihood that this exception may occur.

RateLimitExceededException

A RateLimitExceededException is thrown by all methods of an Optimizely Community API service when an application issues too many requests over a short period of time. All requests issued to Optimizely Community are tallied and compared against the rate limit. When an application exceeds the rate limit, Optimizely Community API stops processing requests until a certain time has elapsed (a "request interval").

The exception provides additional information to help the application regulate its request rate. That information includes:

  • RequestInterval – The length of time in which requests are tallied.
  • RequestsIssued – The number of requests already issued in the request interval.
  • RequestLimit – The maximum number of requests allowed in a given request interval.
  • RetryAfter – The time remaining until the application may resume issuing requests.

If your application regularly encounters this exception, consider:

  • Optimizing your code to minimize unnecessary API calls
  • Caching data that is frequently accessed
  • Actively regulating the application's request rate to ensure that the application never encounters the issue
  • Implementing logic to pause and retry requests after reaching the limit

SocialCommunicationException

An SocialCommunicationException is thrown by Optimizely Community API service methods when a request encounters a fundamental communication issue.

This error most commonly occurs when:

  • The application cannot connect or communicate with Optimizely Community API cloud services.
  • A request from the application exceeds the configured timeout.

SocialException

A SocialException is thrown by Optimizely Community API service methods when a request encounters an unexpected error scenario. The exception contains a message, status code, error code, and additional reasoning to describe the error further.

This error most commonly occurs when:

  • The application's configuration is missing or malformed.
  • The platform encountered an unexpected service error.

Feature exceptions

The individual services of the Optimizely Community API may also throw exceptions unique to the feature they support. Information on feature-specific exceptions can be found in the documentation for each API.

Reference and IDs

The Optimizely Community API has two means of identifying data: by reference and by ID. The structure and function of these classifiers are similar, but there are important semantic distinctions between them. See also: Work with Optimizely Community API References.

Ids

The Id classes that appear in each Community API feature pertain specifically to that feature's entities. Their values are internally-generated and used to distinguish individual entities within the system.

Id classes conform to the following naming convention: {Feature-Name}Id. Examples include:

  • CommentId
  • GroupId
  • WorkflowId

Id classes are accepted by the platform's services when retrieving specific data instances.

Reference

The Reference class that appears in the Optimizely Community API refers to users or resources outside the platform. References identify entities in other systems. Use a reference value to establish relationships between social content and resources or users to which that content applies.

The developer defines the value contained within a reference class. It contains the information necessary to identify or classify the resource or user to which social content is related.

The platform provides a Reference class that is used to identify any target entity in your application. For example, a resource, like Optimizely CMS content, or a product or a user, like an Optimizely CMS user.

Best practices for defining references

As a developer, you are free to define references as it suits your application. Ultimately, you want to ensure that your reference scheme is:

  • Capable of uniquely identifying your application's entities
  • Capable of being interpreted by your application
  • Robust enough to support your application's inevitable enhancements and changes

You are accustomed to considering identifiers unique IDs, such as GUIDs or hashes. These are often sufficient to identify data within a single system but may be insufficient when integrating multiple systems. When designing your scheme for defining reference values, consider the following factors:

  • Platform – In what platform does your resource or user reside?
  • Provider – Does that platform deliver resources or users through different providers?
  • Classification – What type of data is being referenced? Is it content, a product, a CMS user, or an ecommerce customer?
  • Categorization – Is there a taxonomical nature to a resource or a user's identification?
  • Facets – Do you intend to refer to a facet of some resource, like a product's price or color?

These considerations play a role in designing a meaningful reference scheme.

A URI or similar namespace scheme provides an ideal template for a reference. Consider the following example of a reference scheme that might be applied to ecommerce content:

resource://optimizely/commerce/{product-identifier}/{variant-identifier}/{facet-identifier}

This example accounts for the content's classification, platform, hierarchical identifiers, and facets.

Criteria

The Optimizely Community API's services let you retrieve custom result sets of the content which you are managing with it. These services accept criteria that dictate how to retrieve a result set. A class named Criteria<TFilter> encapsulates the specifications necessary to retrieve a collection of results from one of the platform services.

Filter

The type parameter TFilter identifies the class that encapsulates the filter specifications applicable to the service and the content it manages. The particular filter class required by a service is identified in the signature of its retrieval methods.

The Filter property accepts an instance of the filter class, which captures the specifications you want to refine a result set.

PageInfo

The PageInfo property accepts an instance of a class by the same name, which defines the specifications by which a result set is paginated into collections of a fixed number of results.

The PageInfo class captures a page size, representing the maximum number of results to retrieve. The page size must be greater than or equal to zero. If the page size is not specified, a default of 10 items is applied.

PageInfo also captures a page offset, representing the index (zero-based) from which to begin retrieving results. The page offset must be greater than or equal to zero.

PageInfo also lets the user specify if they want to calculate a total result count for the query. This count is returned with the TotalCount property on the ResultPage. By default, no total count is calculated.

Best practices for paginating results

When optimizing your implementation, your page size, page offsets, and total count are important. Large page sizes or deep offsets can negatively impact the performance of your content retrieval. Consider your request size, volume, and user experience to find the appropriate balance when determining your application's pagination strategy. Additionally, retrieving the TotalCount for a query when it is not needed adversely affects the time it takes to return a ResultPage.

OrderBy

The OrderBy property accepts a collection of rules describing how to sort the result set. An instance of a class named represents each sorting ruleSortInfo.

An instance of the SortInfo class identifies the field on which to sort and the direction in which to sort. For example, you might sort a result set of comments by the field representing their publication date in descending order.

A subset of the fields on the platform's data models is available for sorting. This curated set of fields is exposed through classes that adhere to a particular convention. These fields are statically exposed on classes named {Feature-Name}SortFields. For example, CommentSortFields and RatingSortFields.

The sorting rules identified in the collection are processed in order by the service, which executes the result retrieval. Each subsequent rule in the collection represents a fallback if multiple results share a matching value in the field identified by the preceding sorting rule. For example, suppose you sort ratings by their value. In that case, you might specify a fallback of the ratings' modification date to ensure that the platform consistently orders ratings with the same value.

Best practices for sorting results

The platform cannot guarantee the order of results, from request to request, if a field targeted for sorting contains matching values for multiple result items. If consistency in result ordering is relevant, specifying one or more fallback sorting rules is important. Consistency is particularly important if your application lets users navigate through multiple pages of result items.

The sorting of string values will occur based on the Unicode value of a character. If your application requires alternative ordering for a property, you should standardize the data in code and store it as a duplicate property on the extension data.

Result sets

The services of the Optimizely Community API, which expose bulk retrieval capabilities, deliver their results in a paginated fashion. A page of results is represented with a class named ResultPage<T>.

Results

The type parameter T identifies the class representing the model for the data to be returned. For example, Comment or Rating. The Results property gets the collection of individual result items that comprise the page.

TotalCount

The TotalCount property provides a total count of items resulting from the query. For example, a product has 20 comments. In requesting this product's comments, a page size of 10 is specified. The resulting page of comments would include 10 items, while its TotalCount property would have a value of 20. A total count is calculated when the CalculateTotalCount property of the PageInfo associated with your criteria is assigned a value of true. If CalculateTotalCount is set to false, the total count is -1.

Info

The Info property refers to the paging specifications, which were specified when the request that produced the page was issued.

HasMore

The HasMore property provides a boolean that denotes whether the query has found more items beyond the page returned. An example of this would be a query with 11 results in the database, and a query is issued with a PageSize of 10. The ResultPage would return 10 results and have a HasMore value of true. This provides a developer insight into whether an additional query with a PageOffset of 10 would return any items in the ResultPage. In this example, if a second query were issued, it would return 1 item in the ResultPage and have a HasMore value of false.

Composites

Every application has unique needs concerning the structure of its social content. Applications have different systems to integrate with, different visions of what community-generated content is comprised of, and different entities and actions to moderate. An application needs the freedom to store, relate, and present social content in a form that it determines appropriate. With this in mind, the features of the Optimizely Community API distill social concepts to their essence and invite data extensibility by allowing its native entities to be composed with custom data models.

  • What is a composite?
  • Defining extension data
  • Composite criteria
  • Filtering composites
  • Sorting composites

What is a composite?

The Optimizely Community API encourages data extensibility by compiling native platform entities with custom extension data. Extension data is a .NET class, defined within your application, intended to capture additional details necessary to shape a platform entity to meet your application's needs.

The platform's services encapsulate the relationship between their entities and extension data with the Composite class. The Composite class represents a simple pairing, an instance of a native platform entity, and its associated extension data.

Define extension data

Extension data is a .NET class, defined within your application, and intended to capture additional details necessary to shape a platform entity to meet your application's needs. As you design the classes that represent your extension data, consider the following:

  • Queryability – The platform can sort and filter composite result sets according to a select set of primitive value types within your extension data. If you intend to filter or sort by particular extension data values, it is important to design your extension data class accordingly. (See Filtering Composites.)
  • Maintainability – Anticipate the likelihood of future enhancements to your application's data and the impact of changes on your classes or business logic. Think of your extension data as a schema and approach its design carefully.
  • Performance – Keep extension data light to minimize the likelihood of performance penalties in its transfer.

Extension data is subject to the realities and limitations of today's serialization engines. To ensure that your data can be stored and retrieved, the extension data class must abide by the following constraints:

  • It must have a public, parameter-less constructor.
  • It must not refer to nested data in a polymorphic manner. For example, the class must not refer to a child as the Object type.
  • It must not contain self-references or referential loops.
  • The class name and the assemblies' names and namespaces containing it must remain stable to ensure that the platform can identify the stored data.
  • An instance of this data contributes to the total size of a request to the platform. Minimize the size of this data to avoid exceeding platform size restrictions.

If these constraints are not respected, you may encounter errors while storing and retrieving composites.

You should use only classes defined within your application when defining extension data. The data models of this platform are not guaranteed to be serializable. Defining your own classes, rather than utilizing those of a third-party library, also helps to future-proof your schema. This mitigates the risk of volatility within your dependencies.

When defining extension data, consider these additional caveats:

  • DateTime values in extension data are stored and returned as Universal Time Coordinated (UTC).
  • DateTime precision is consistent up to the millisecond value.
  • There is no support for the Decimal type in the Optimizely Community API Platform. As a result, a Decimal value is stored as a double and can be subject to a rounding error.

Composite criteria

The Optimizely Community API lets you retrieve result sets of composite data like its standard entities. Each platform service that supports Composites provides methods for retrieving them. The services delivering result sets of composite data accept composite criteria. These criteria are represented by a class named CompositeCriteria\<TFilter, TExtension>.

The CompositeCriteria class extends the standard Criteria class, incorporating its capabilities. The filters and other specifications exposed by Criteria may be applied in conjunction with the additional enhancements afforded by the CompositeCriteria class.

ExtensionFilter

The TExtension type parameter identifies the type of extension data to be retrieved. This serves as an implicit filter; only Composites with extension data of this type are retrieved.

The ExtensionFilter property accepts a Boolean expression capable of filtering your result set by values in your extension data. This expression is represented as a tree structure and may combine multiple Boolean expressions with logical operators (like "AND"), also provided by the platform. For information regarding the construction of these expressions, see Filtering Composites.

IncludeSubclasses

The IncludeSubclasses property accepts a value, which indicates if the result set should include items bearing extension data that implement a subclass of the type identified by the TExtension type parameter.

  • True indicates that the result set may include composites where TExtension appears anywhere within the type hierarchy of their associated extension data. This is the default behavior.
  • False indicates that the result set includes only composites where their extension data is explicit of the TExtension type.

Filter composites

Composites lets you extend the platform by composing platform entities with supplemental data of their own design. This feature is enhanced by the ability to define custom filters for result sets, which include that data. This type of refinement is a Filter Expression.

Filter Expressions are Boolean expressions, represented as tree structures, which can filter a result set of Composites by values included within their extension data. Consider an example where an application composes a comment with extension data via the following definition:

public class MyCommentExtension {
  public int LuckyNumber {
    get;
    set;
  }
  public string FavoriteTeam {
    get;
    set;
  }
  public DateTime Birthday {
    get;
    set;
  }
}

In this example, your application requires you to filter composite comments to those with a LuckyNumber of 7 and a Birthday before 1990. A filter that accounts for these specifications can be represented as the following expression tree:

The platform provides the tools necessary to construct such an expression tree. The primary point of access for doing so is a class named FilterExpressionBuilder<TExtension>.

The FilterExpressionBuilder exposes convenient methods and operator overloads for individual Boolean and logical operators available to developers when defining Filter Expressions. This class's TExtension type parameter identifies the type of extension data that the resulting expression is intended to target.

The operators available for defining filters include:

Builder methodClassDescriptionBuilder Operator Overloads
FieldFieldExpressionRepresents a field. 
EqualToEqualToExpressionRepresents an equality comparison.==
ContainsContainsExpressionRepresents an equality comparison in collections 
AnyAnyExpressionRepresents the inclusion of a field value in a given collection 
GreaterThanGreaterThanExpressionRepresents a greater than comparison>
GreaterThanOrEqualToGreaterThanOrEqualToExpressionRepresents a greater than or equal to comparison> =
LessThanLessThanExpressionRepresents a less than comparison<
LessThanOrEqualToLessThanOrEqualToExpressionRepresents a less than or equal to comparison<=
AndAndExpressionRepresents a logical AND of a collection of filter expressions.&
OrOrExpressionRepresents a logical OR of a collection of filter expressions.

The expressions representing Boolean operators, which are available within the platform, can compare fields of the following .NET data types:

  • String
  • Boolean
  • Int
  • Long
  • Double
  • DateTime

Continuing the above example, consider how a developer would leverage the FilterExpressionBuilder to construct the necessary Filter Expression.

var luckyNumberOf7 = FilterExpressionBuilder<MyCommentExtension>.Field(d => d.LuckyNumber).EqualTo(7);

The snippet above constructs a Boolean expression, which evaluates the LuckyNumber field of our extension data for a value of 7. This example features two method calls:

  • The Field method accepts a lambda expression, which selects the extension data field we intend to represent in the Filter Expression.
  • The FieldExpression's EqualTo method accepts a value, constructing an EqualToExpression where our FieldExpression represents its left operand and the value represents its right operand.

The result of this operation is the expression tree below:

var bornBefore1990 = FilterExpressionBuilder<MyCommentExtension>.Field(d => d.Birthday).LessThan(new DateTime(1990, 1, 1));

Similarly, the snippet above constructs a Boolean expression that evaluates the Birthday field of your extension data for a value before the year 1990. The result of this operation is the expression tree below:

You can combine these two Boolean expressions into a single Filter Expression by logically ANDing them, as demonstrated in the snippet below:

var combinedExpression = FilterExpressionBuilder<MyCommentExtension>.And(luckyNumberOf7, bornBefore1990);

The result of this operation, which completes your filter for this example, is the expression tree below:

To put these snippets in context, the construction of criteria reflecting a request for composite comments might appear as follows:

var luckyNumberOf7 = FilterExpressionBuilder<MyCommentExtension>.Field(d => d.LuckyNumber).EqualTo(7);
var bornBefore1990 = FilterExpressionBuilder<MyCommentExtension>.Field(d => d.Birthday).LessThan(new DateTime(1990, 1, 1));
var combinedExpression = FilterExpressionBuilder<MyCommentExtension>.And(luckyNumberOf7, bornBefore1990);
var criteria = new CompositeCriteria<Comment, MyCommentExtension>
{                
    ExtensionFilter = combinedExpression
};

Best practices for defining filter expressions

  • Elaborate filter expressions can impact the performance of your requests. For optimal performance, minimize the complexity and depth of your expressions.
  • Changes to the structure of your extension data classes may result in malformed expressions.
  • Malformed expressions may result in unexpected results or empty result sets. Think of your extension data as a schema and carefully approach its design.

Filter expressions

The examples for each filter expression below assume the following comment extension:

public class MyCommentExtension {
  public int LuckyNumber {
    get;
    set;
  }
  public List<string> FavoriteTeams {
    get;
    set;
  }
  public DateTime Birthday {
    get;
    set;
  }
}
Any expression

Use the Any expression to filter both single-value and multi-value extension fields by a list of values. As an example of using the Any expression with a single-value extension field, assume that we want to read all comments for which the single-value LuckyNumber extension field matches any of three drawn lucky numbers. The following code shows how this is done with the Any expression:

var drawnLuckyNumbers = new List<long>{3, 7, 9};
var commentsWithDrawnLuckyNumbers = FilterExpressionBuilder<MyCommentExtension>.Field(ext => ext.LuckyNumber).Any(drawnLuckyNumbers);
var criteria = new CompositeCriteria<Comment, MyCommentExtension>
{                
  ExtensionFilter = commentsWithDrawnLuckyNumbers
};

As an example of using the Any expression with a multi-value extension field, assume that we want to read all comments for which the multi-value favoriteTeams extension field contains either "New England Patriots" or "Boston Red Sox". The following code shows how this is done with the Any expression.

var mostFavoriteTeams = new List<string>{"New England Patriots", "Boston Red Sox"};
var commentsWithMostFavoriteTeams = FilterExpressionBuilder<MyCommentExtension>.Field(ext => ext.FavoriteTeams).Any(mostFavoriteTeams);
var criteria = new CompositeCriteria<Comment, MyCommentExtension>
{                
  ExtensionFilter = commentsWithMostFavoriteTeams
};
Contains expression

The Contains expression can be used to filter both single-value and multi-value extension fields by a single value. As an example of using the Contains expression with a single-value extension field, assume that we want to read all comments for which the single-value LuckyNumber extension field matches drawn lucky number 7. The following code shows how this is done with the Contains expression:

var luckyNumber = 7;    
var commentsWithLuckNumber = FilterExpressionBuilder<MyCommentExtension>.Field(ext => ext.LuckyNumber).Contains(luckyNumber);
var criteria = new CompositeCriteria<Comment, MyCommentExtension>
{                
  ExtensionFilter = commentsWithLuckNumber
};

As an example of using the Contains expression with a multi-value extension field, assume that you want to read all comments for which the multi-value favoriteTeams extension field contains "Boston Celtics". The following code shows how this is done with the Contains expression.

var favoriteTeam = "Boston Celtics";
var commentsWithFavoriteTeam = FilterExpressionBuilder<MyCommentExtension>.Field(ext => ext.FavoriteTeams).Contains(favoriteTeam);
var criteria = new CompositeCriteria<Comment, MyCommentExtension>
{                
  ExtensionFilter = commentsWithFavoriteTeam
};
EqualTo expression

The EqualTo expression is used to filter documents by an extension field whose value equals a given value. The EqualTo expression in the following example will match any comments with a Birthday on new year 2000.

var newYear2000 = new DateTime(2000, 1, 1);
var commentsWithMatchingBirthday = FilterExpressionBuilder<MyCommentExtension>.Field(d => d.Birthday).EqualTo(newYear2000);
var criteria = new CompositeCriteria<Comment, MyCommentExtension>
{                
  ExtensionFilter = commentsWithMatchingBirthday
};
LessThanOrEqualTo expression

The LessThanOrEqualTo expression filters documents by an extension field whose value is less than or equal to a given value. The LessThanOrEqualTo expression in the following example will match any comments with a Birthday on or before new year 2000.

var newYear2000 = new DateTime(2000, 1, 1);
var commentsWithMatchingBirthday = FilterExpressionBuilder<MyCommentExtension>.Field(d => d.Birthday).LessThanOrEqualTo(newYear2000);
var criteria = new CompositeCriteria<Comment, MyCommentExtension>
{                
  ExtensionFilter = commentsWithMatchingBirthday
};
GreaterThanOrEqualTo expression

The GreaterThanOrEqualTo expression filters documents by an extension field whose value is greater than or equal to a given value. The GreaterThanOrEqualTo expression in the following example will match any comments with a Birthday on or after new year 2000.

var newYear2000 = new DateTime(2000, 1, 1);
var commentsWithMatchingBirthday = FilterExpressionBuilder<MyCommentExtension>.Field(d => d.Birthday).GreaterThanOrEqualTo(newYear2000);
var criteria = new CompositeCriteria<Comment, MyCommentExtension>
{                
  ExtensionFilter = commentsWithMatchingBirthday
};
LessThan expression

The LessThan expression filters documents by an extension field whose value is less than a given value. The LessThan expression in the following example matches any comments with a Birthday before 2000.

var newYear2000 = new DateTime(2000, 1, 1);
var commentsWithMatchingBirthday = FilterExpressionBuilder<MyCommentExtension>.Field(d => d.Birthday).LessThan(newYear2000);
var criteria = new CompositeCriteria<Comment, MyCommentExtension>
{                
  ExtensionFilter = commentsWithMatchingBirthday
};
GreaterThan expression

The GreaterThan expression filters documents by an extension field whose value exceeds a given value. The GreaterThan expression in the following example will match any comments with a Birthday after new year 2000.

var newYear2000 = new DateTime(2000, 1, 1);
var commentsWithMatchingBirthday = FilterExpressionBuilder<MyCommentExtension>.Field(d => d.Birthday).GreaterThan(newYear2000);
var criteria = new CompositeCriteria<Comment, MyCommentExtension>
{                
  ExtensionFilter = commentsWithMatchingBirthday
};
And expression

The And expression filters documents by one or more sub-expressions where a document is matched by all the sub-expressions. The And expression in the following example will match any comments with a Birthday in the year 2000.

var startYear2000 = new DateTime(2000, 1, 1);
var endYear2000 = new DateTime(2000, 12, 31);
var commentsMatchingBirthday1 = FilterExpressionBuilder<MyCommentExtension>.Field(d => d.Birthday).GreaterThanOrEqualTo(startYear2000);
var commentsMatchingBirthday2 = FilterExpressionBuilder<MyCommentExtension>.Field(d => d.Birthday).LessThanOrEqualTo(endYear2000);
var commentsWithBirthdayInYear2000 = FilterExpressionBuilder<MyCommentExtension>.Field(d => d.Birthday).And(commentsMatchingBirthday1, commentsMatchingBirthday2);
var criteria = new CompositeCriteria<Comment, MyCommentExtension>
{                
  ExtensionFilter = commentsWithBirthdayInYear2000
};
Or expression

The Or expression is used to filter documents by one or more sub-expressions where any of the sub-expressions matches a document. The Or expression in the following example will match any comments with a Birthday in year 2000 Or LuckyNumber 7.

var startYear2000 = new DateTime(2000, 1, 1);
var endYear2000 = new DateTime(2000, 12, 31);
var commentsMatchingBirthday1 = FilterExpressionBuilder<MyCommentExtension>.Field(d => d.Birthday).GreaterThanOrEqualTo(startYear2000);
var commentsMatchingBirthday2 = FilterExpressionBuilder<MyCommentExtension>.Field(d => d.Birthday).LessThanOrEqualTo(endYear2000);
var commentsWithBirthdayInYear2000 = FilterExpressionBuilder<MyCommentExtension>.Field(d => d.Birthday).And(commentsMatchingBirthday1, commentsMatchingBirthday2);
var luckyNumber = 7;
var commentsWithLuckyNumber = FilterExpressionBuilder<MyCommentExtension>.Field(ext => ext.LuckyNumber).Contains(luckyNumber);
var theWinner = FilterExpressionBuilder<MyCommentExtension>.Field(d => d.Birthday).Or(commentsWithBirthdayInYear2000, commentsWithLuckyNumber);
var criteria = new CompositeCriteria<Comment, MyCommentExtension>
{                
  ExtensionFilter = theWinner
};

Sort composites

Just as fields represented within extension data may be referenced in filtering Composite result sets, they may also be applied in sorting result sets. Sorting rules are defined with the CompositeCriteria class, just as they are for the standard Criteria class. Its OrderBy property accepts a collection of rules describing how to sort the result set. An instance of a class named represents each sorting ruleSortInfo.

An instance of the SortInfo class identifies the field and the direction on which to sort. A field represented in your extension data may be identified in the construction of SortInfo by leveraging the FilterExpressionBuilder. See Filtering Composites.

Consider an example where an application composes a comment with extension data with the following definition:

public class MyCommentExtension {
  public int LuckyNumber {
    get;
    set;
  }
  public string FavoriteTeam {
    get;
    set;
  }
  public DateTime Birthday {
    get;
    set;
  }
}

The snippet below demonstrates the construction of an instance of SortInfo, targeting the LuckyNumber field of such an extension:

var sortField = new SortField(FilterExpressionBuilder<MyCommentExtension>.Field(d => d.LuckyNumber));
var sortingRule = new SortInfo(sortField, true);
var criteria = new CompositeCriteria<Comment, MyCommentExtension>
{                
  OrderBy = new List<SortInfo> { sortingRule }
};

In this example, an instance of SortField is constructed. It accepts a FieldExpression representing the LuckyNumber field of your extension data. Next, an instance of SortInfo is constructed to refer to this SortField, and assigned to the criteria as a sorting rule.

Sorting rules targeting the fields represented within extension data may be applied to your criteria in conjunction with those targeting the curated set of sort fields available for platform entities. See Criteria.

Asynchronous methods

In addition to synchronous methods, the Optimizely Community API services expose method overloads for use in an asynchronous programming model. Suppose the needs of your application are such that you cannot block an application thread while invoking the Optimizely Community API services. In that case, you can employ a corresponding overload of that method.

In a synchronous operation, the calling thread cannot continue until the API completes its operation. On the other hand, when these overloads are invoked using the appropriate asynchronous .NET techniques, it can now run to completion without blocking. Meanwhile, the calling thread in your application can perform its additional business logic in parallel. Being able to perform tasks in parallel can improve the overall responsiveness and performance of your application.

All asynchronous methods in the Optimizely Community API framework end with the Async suffix and return a .NET Task object. A Task object is used to represent an asynchronous operation. For more details, refer to Microsoft's documentation for Task-based Asynchronous Programming. An Async overload is available for any Optimizely Community API method that can block the calling thread while communicating with the framework's cloud services to operate.

You can use C#'s async and await keywords to perform long-running work without blocking the calling thread. For more details, see Microsoft's documentation on Asynchronous Programming with async and await.

Optimizely Community API asynchronous overloads are discussed in detail with code examples alongside their synchronous versions in the Optimizely Community API feature documentation.