This is documentation for the current major version Apprenda 7.
Older versions are also available.

Extending the Apprenda Platform

This page describes how to extend normal Platform behaviors for integrating with services outside the Platform.

Guest Applications as Service-Oriented Extensions

The Platform runtime exposes a dynamically configurable service-oriented extension system that allows Developers to publish guest applications with functionality that extends the default Platform business workflows and then tell the Platform to call those services during normal workflow operations. The Platform API contains service contracts for core workflow extension points, each responsible for separate business service workflows. By extending these base classes in a WCF service or group of services, publishing, and then configuring the Platform in real-time, Platform owners can achieve a huge amount of customization. For example, you may want to capture information about new Users that are created in the system and communicate that information to a third-party service.

The configuration of these extensions is performed in the Operations Center and is based on Custom Settings, so it is therefore highly dynamic. Because extension services are guest apps on the Platform, they gain the benefit of Apprenda’s application lifecycle management, allowing Platform Operators to test variations of their extensions. Additionally, multiple extension services can be called in succession, allowing Platform Operators to build workflows from extension services published by Developers.

Developing Extension Services

The base classes for Apprenda’s extension services can be found in the Apprenda.SaaSGrid.Extensions namespace, which is located in the SaaSGrid.API assembly delivered with the platform SDK.

Base Classe

Authentication & Signup Workflow:
Apprenda.SaaSGrid.Extensions.CitadelExtensionServiceBase

User Administration Workflow:
Apprenda.SaaSGrid.Extensions.AccountPortalExtensionServiceBase

Developer Workflow:
Apprenda.SaaSGrid.Extensions.DeveloperPortalExtensionServiceBase

Platform Operator Workflow:
Apprenda.SaaSGrid.Extensions.LogAggregatorExtensionServiceBase

It is recommended that WCF services receiving logs from the Platform should use the Authorized User Access Model. This access level will make sure that only authorized and authenticated entities can push logs to the WCF service. If you have any more questions about hardening your WCF service and taking advantage of integration to popular operational intelligence platforms contact your support representative.

Storefront Workflow:
Apprenda.SaaSGrid.Extensions.StoreFrontExtensionServiceBase

Deployment Workflow for any type of component:
Apprenda.SaaSGrid.Extensions.PlacementExtensionServiceBase

Presentation Deployment Workflow (deprecated: Apprenda.SaaSGrid.Extensions.PlacementExtensionServiceBase is preferred):
Apprenda.SaaSGrid.Extensions.PresentationExtensionServiceBase

Storage Deployment Workflow (deprecated: Apprenda.SaaSGrid.Extensions.PlacementExtensionServiceBase is preferred):
Apprenda.SaaSGrid.Extensions.StorageExtensionServiceBase

To build a service whose methods will be called by the Platform extension points, Developers should create WCF services that implement one or more of these base classes and override the methods that they want to use.  Data sent to extension services uses a set of objects located in the namespace Apprenda.SaaSGrid.Extensions.DTO, which is also contained in the SaaSGrid.API assembly.

Below are some examples on implementing an extension:

Example 1

This is an example of a WCF service class that implements the CitadelExtensionServiceBase, and will therefore be capable of handling Authentication & Signup hooks:

namespace MyApprendaExtensionServices.Citadel
{
    public class ExtensionService : CitadelExtensionServiceBase    
    {        
        public override void OnTenantOnBoarding(TenantOnBoarderDTO tenant)
        {
            // your extension logic here           
        }
 
        public override void OnTenantOnBoarded(TenantOnBoarderDTO tenant)
        {
            // your extension logic here
        }
    }
};

Along with its accompanying System.ServiceModel configuration in the App.config:

<service name="MyApprendaExtensionServices.Citadel.ExtensionService" 
         behaviorConfiguration="ApprendaServiceBehavior">
 <endpoint address="net.tcp://localhost:40000/ICitadelExtensionService"
         binding="netTcpBinding"
         bindingConfiguration="DefaultTcpBinding"
         behaviorConfiguration="ApprendaEndpointBehavior"
         contract="Apprenda.SaaSGrid.Extensions.ICitadelExtensionService"/>
</service>

This WCF service should be packaged into an archive for deployment like any other Platform guest application and promoted through the publishing stages in the Developer Portal.

Example 2

This is an example of a WCF service class that implements the LogAggregationExtensionServiceBase, and will be capable of handling an operator hook point for log aggregation.

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class LogService : LogAggregatorExtensionServiceBase
{
	public override void OnLogsPersisted(IEnumerable logs)
	{
	    // Your extension logic goes here
	}
}

 

Configuring the Platform to Use Extension Services

Custom Settings in the Operations Center are used to tell the Platform about the extension services to employ during standard workflows. There is a Custom Setting for each of the core services that can be extended:

Authentication & Signup Workflow Setting Name:

  • CitadelExtServices

User Administration Workflow Setting Name:

  • AccountPortalExtServices

Developer Workflow Setting Name:

  • DeveloperPortalExtServices

Platform Operator Workflow Setting Name:

  • Apprenda.Logging.ExternalServiceAppVersion

Storefront Workflow Setting Name:

  • StoreFrontExtServices

Deployment Workflow Setting Names by component type (for services implementing Apprenda.SaaSGrid.Extensions.PlacementExtensionServiceBase):

  • Deployment.AspNetPlacementExtServices (for .NET user interface components); may also be used for the deprecated base class Apprenda.SaaSGrid.Extensions.PresentationExtensionServiceBase
  • Deployment.DBPlacementExtServices (for database components); may also be used for the deprecated base class Apprenda.SaaSGrid.Extensions.StorageExtensionServiceBase
  • Deployment.ServicePlacementExtServices (for WCF and Windows service components)
  • Deployment.WarPlacementExtServices (for wars)

Presentation Workflow Setting Name (deprecated: any value configured for this setting will be migrated to Deployment.AspNetPlacementExtServices):

  • PresentationExtServices

Storage Workflow Setting Name (deprecated: any value configured for this setting will be migrated to Deployment.DBPlacementExtServices):

  • StorageExtServices

Custom Setting Values

The values for these settings should be a comma-delimited list of application aliases corresponding with the unique application and version aliases (for application  in the Sandbox stage), followed by the service class name that is being called. 

Note: Extensions will not be invoked when deploying a service hosting one of the extensions that should be used for service deployment because this would result in a recursive loop that cannot complete.

For example, to configure the Platform to call the ExtensionService in a published application with alias ‘myextservice’ during account signup, the ExtensionService must implement Apprenda.SaaSGrid.Extensions.CitadelExtensionServiceBase, override one or more hookpoints, be configured to expose that contract endpoint, and it must be published. Then, the setting ‘CitadelExtServices’ should have a value of ‘myextservice’, or ‘myextservice(v1)’, which specifies a target version of the application. If Developers publish version two with the alias v2, the setting can be updated to ‘myextservice(v2)’ and that extension service will be called during the next account signup workflow that fires. To call both versions of this application, or call multiple application/version pairs during the same workflow, use a comma-delimited, like this:

Setting Name: CitadelExtServices
Setting Value: myextservice(v1)/ExtensionService, myextservice(v2)/ExtensionService, myotherextservice(v1)/ExtensionService

During account creation, the contract endpoints for ICitadelExtensionService on the WCF service called ‘ExtensionService’ will be called in order.

Note: Applications in the Published stage do not require a specified version alias, only ones in the Sandbox stage do. If no version is specified, it will call whatever version is Published.

Available Hook Points

The following is an explanation of each hook point that an extension service can implement.

Authentication & Signup Workflow Hooks
The following service methods will be called by Apprenda’s Citadel service, which handles account onboarding and authentication.

  • OnFailedLogin
  • OnTenantOnBoarding
  • OnTenantOnBoarded
  • OnUserLogin
  • OnUserLogout
  • ValidatePassword

User Administration Workflow Hooks
The following service methods will be called by Apprenda’s AccountPortal service, which handles customer and Tenant account management:

  • OnCreatingUser
  • OnUserCreated
  • OnRemovingUser
  • OnUserRemoved
  • OnUpdatingUser
  • OnUserUpdated

Developer Workflow Hooks
The following service methods will be called by Apprenda’s DeveloperPortal service, which handles guest application publishing:

  • OnPromotingVersion
  • OnVersionPromoted
  • OnDemotingVersion
  • OnVersionDemoted

Platform Operator Workflow Hooks
The following service methods will be called by Apprenda’s Logging service, which handles log publishing:

  • OnLogsPersisted

    • This endpoint is called in frequent intervals and is passed an array of log messages from the Platform. All logs for all applications will be pushed to this endpoint
    • Parameter: An array Apprenda.SaasGrid.Extension.DTO.LogMessageDTO objects

It is recommended that automatic scaling is configured for the WCF service receiving logs from the Platform. Although there is no performance penalty when you subscribe to the OnLogsPersisted hook point, using automatic scaling will allow the component to scale with the dynamic demand of logging on the Platform. 

Storefront Workflow Hooks
The following service methods will be called by Apprenda's Storefront service, which handles the Platform’s authorization mechanisms such as subscriptions:

  • OnPurchasingSubscription
  • OnSubscriptionPurchased
  • OnActivatingSubscriptions
  • OnSubscriptionsActivated
  • OnExpiringSubscriptions
  • OnSubscriptionsExpired
  • OnSuspendingSubscriptions
  • OnSubscriptionsSuspended
  • OnCancellingSubscriptions
  • OnSubscriptionsCancelled

Deployment Workflow for all component types
The following service methods will be called by Apprenda's DeveloperPortal service during deployment of components:

  • FilterHostsForNewWorkload
  • FilterHostsForNewTenantShard

Presentation Workflow Hooks
The following service methods will be called by Apprenda's DeveloperPortal service during deployment of UI components:

  • FilterHostsForPartition
  • FilterHostsForTenantShard

Storage Workflow Hooks
The following service methods will be called by Apprenda's DeveloperPortal service during deployment of storage components:

  • FilterHostsForPartition

Retrieving Contextual Information

The Apprenda Platform allows Developer to access contextual information regarding the current Organization (refer to the Contexts documentation for more information). When using extensions, a new TenantContext is appended to the stack for the Organization that developed the extension, this means that TenantContext.Current won't retrieve the running Organization but the Developer. In order to retrieve the right information, you can use the following method:

private TenantContext EstablishProperContext()
{
      if (TenantContext.Current.History.Skip(1).Any())
      {
           /*Because this will run as a single tenant app, the top tenant context is the tenant ID for that deployed the extension application
           In order to get the ID for the executing tenant, we have to move up the stack once.*/
           return TenantContext.NewTenantContext(TenantContext.Current.History.Skip(1).First().TenantId);
      }
      else
      {
           return TenantContext.NewTenantContext(TenantContext.Current.TenantId);
      }
}

Extensions Example

The example is a simple Apprenda application that implements all four extension interfaces. The application logs an info message every time each extension method is called. 

Extension Example

Extensions Library and Support

Extensions are an excellent way to enhance the Platform functionality to fit your particular need. We dedicated an entire forum just for them in the Apprenda support website. In this forum you will be able to download extensions that were developed by the Apprenda support team and are ready to be deployed, and you can ask questions and get general implementation information.

We are always adding new extensions; if you have an idea for one, e-mail us at support@apprenda.com. Also, if you have developed an extension yourself that wish to publish for the community, please feel free to post it!

Extensions Library and Support