Extensions
How to Extend Squidex and the Different Extension Points for Customization.
Last updated
How to Extend Squidex and the Different Extension Points for Customization.
Last updated
This document describes how to write extensions for Squidex. We assume that you know the basic principles of C# and ASP.NET Core. Otherwise, it might be very hard to write custom extensions.
We use interfaces for all components, which can then be replaced with custom implementations. The default dependency injection system is used to register services. (see https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection).
Furthermore, you can extend Squidex with custom HTTP endpoints. Due to the static nature of the Management UI (which is built with Typescript and Angular and has a compilation and bundling process), you cannot extend the UI, except in a few cases where its been made possible.
Read the following article to understand how to write custom editors for the Management UI:
So far (as of October 2019), Squidex has a limited plugin architecture that can be used for most cases. In this section we will give you an introduction how to write this type of plugin, and how to register it in Squidex.
In this tutorial we use Squidex.Extensions
project as an example, which also contains a sample plugin.
Checkout the source code from GitHub:
You only need the source code for development. There are other approaches on how to deploy the newest version of Squidex with your plugin.
First, you need to create a new .NET class library to the backend solution:
Ensure that you target netcoreapp3.0
.
Then add references to the following other projects in the solution:
Squidex.Domain.Apps.Entities
Squidex.Web
This will implicitly create references to all other projects that might be needed.
The reference projects contain interfaces as well as implementations - which is a problem, because it's hard to figure out which classes should be used in custom plugins. Implementations are subject to change and should not be used directly. Therefore we plan to restructure the content and create implicit contract projects, which don't contain implementation details.
A plugin class is used to register all implementations to Squidex. In this example we create a custom plugin which registers an asset store and keeps all files in memory. We register it only when it's activated via the configuration system, so either from the appSettings.json
file, command line arguments or environment variables.
You can also add multiple implementations to your class library if you have multiple extensions in one project and want to group them together.
Add a reference to your plugin in the Squidex
project.
Furthermore, you need to add the path to your plugin to the configuration, for example to the appSettings.json
file. As we reference the plugin, it will be automatically copied to the output folder when the build or packaging is executed.
There is also a project on GitHub that demonstrates how to create a plugin for SendGrid with an older version of Squidex: https://github.com/squidexcontrib/sendgrid
There are a few extension points that can be used for custom functionality.
Rule actions are used to integrate external systems to Squidex. Therefore, we have written a guide to show you how to write your first rule action here:
You can write your own controllers, but you have to extract them from the ApiController
class. Your controllers are available under the /api
path, because all other requests will be forwarded to the Management UI. The ApiController
enforces this rule and ensures the correct routing.
The Squidex.Infrastructure.Assets.IAssetStore
interface is used to encapsulate storage solutions for assets. Currently there are the following implementations:
AzureBlobAssetStore
: Stores the assets in Azure Blob storage.
GoogleCloudAssetStore
: Stores the assets in Google Cloud.
Read more: https://cloud.google.com/storage/.
MongoGridFsAssetStore
: Stores the assets in MongoDB using GridFS.
Read more: https://docs.mongodb.com/manual/core/gridfs/.
FolderAssetStore
: Stores the assets in the file system.
Recommended implementations:
Amazon S3
The Squidex.Infrastructure.CQRS.Events.IEventStore
is our abstraction for different event store implementations. You can append to events, query them or subscribe to events. Depending on your implementation, you might want to use the pub-sub system for subscriptions. The notification mechanism is provided by the Squidex.Infrastructure.CQRS.Events.IEventNotifier
interface. Currently, there are these implementations as follows:
Squidex.Infrastructure.CQRS.Events.MongoEventStore
: Implementation for MongoDB.
Squidex.Infrastructure.CQRS.Events.GetEventStore
: Implementation for EventStore.
Read more: https://geteventstore.com/.
Recommended implementations:
SQL Databases
The Squidex.Infrastructure.CQRS.Events.IEventConsumerInfoRepository
defines the contract for a system to store the current state of each event consumer.
The Squidex.Infrastructure.Assets.IAssetThumbnailGenerator
interface encapsulates image transformations. We only have an implementation for ImageSharp: https://github.com/SixLabors/ImageSharp
You can provide other implementations for repositories, e.g. for Elastic Search or SQL:
Squidex.Domain.Apps.Entities.Assets.Repositories.IAssetRepository
: Stores metadata about assets such as names and sizes, but not the content itself. It can be challenging to implement the filtering.
Squidex.Domain.Apps.Entities.Contents.Repositoriess.IContentRepository
: Stores the content itself. It can be challenging to implement the filtering.
Squidex.Domain.Apps.Read.History.Repositories.IHistoryEventRepository
: Stores basic history events to show them in the UI.
Squidex.Domain.Apps.Entities.Rules.Repositories.IRuleEventRepository
: Stores the rule events, like an internal job queue.
Squidex.Infrastructure.States.IStore
: Key value store for JSON objects. It contains everything else like comments, apps, schemas, rules, custom indices and settings.
Squidex.Infrastructure.UsageTracking.IUsageTracking
: Stores historic usage information and performance metrics.
Command middlewares are used to handle commands, for example when a new content item is created. They run in a pipeline and can be used for a lot of different purposes. It's safe to implement the ICustomCommandMiddleware
interface which ensures that your commands are running in the correct order.
They accept two parameters. The first is the command context that also includes a reference to the command. The next is a function to call the next command handler. Typical use cases are changes to one domain object, for example default fields for new schemas.
If you can accept the command, handle it and call Complete()
.
Event consumers are invoked when new events are created or when an event consumer is restarted and old events are replayed. You shouldn't raise new events, but of course you can create a new event.