Skip to content

Integration

Integration with subscriptions is achieved through the client module API, which we'll use to define all required components.

As always, start by depending on the required module.

XML
<ProjectReference Include="$(ServicesPath)Subscriptions\ITsynch.Suite.Subscriptions.ClientModule\ITsynch.Suite.Subscriptions.ClientModule.csproj" />
C#
1
2
3
4
5
6
7
public class MyModule : SuiteModule
{
    public override void SetupModule(IModuleBuilder builder)
    {
        builder.DependsOn<SubscriptionsClientModule>();
    }
}

Defining templates

Templates are expected to be found inside \Subscriptions\Templates directory. This path is overridable if required in rare cases, but its not recommended to.

Templates can be placed inside JSON or even text files, but liquid template syntax is required.

JSON
1
2
3
4
5
6
7
{
    "subject": "Warranty claim updated.",
    "body": "Warranty claim {{Claim.Code}} was updated.
    \n Related details specified below:
    \n Subject: {{Claim.Subject}}
    \n Creation date: {{Claim.CreatedAt}}"
}

Along with the template configuration, a name and path are to be specified

C#
1
2
3
4
5
public static class Templates
{
    public static readonly string ClaimUpdatedTemplateName = "subscriptions/warranty-claims/claim-updated";
    public static readonly string ClaimUpdatedTemplatePath = "claim-updated.json";
}

!!!note It might be confusing that the template name looks like a path itself. This is done this way to allow a better organization and administration of the many templates that exist in the system. The actual template path references the path to the directory where we'll find the template file inside Subscriptions/Templates

Using the client module API we can register templates

C#
public class MyModule : SuiteModule
{
    public override void SetupModule(IModuleBuilder builder)
    {
        builder.DependsOn<SubscriptionsClientModule, SubscriptionsClientModuleOptions>(
            options => {
                options.RegisterTemplate(
                Templates.ClaimUpdatedTemplateName,
                Templates.ClaimUpdatedTemplatePath,
                Channel.Email);
            }
        );
    }
}

Defining topics

Just like templates, topics are required to define a name. A description of the subject being exposed is also requested.

C#
1
2
3
4
5
public static class Topics
{
    public static readonly string ClaimUpdatedTopicName = "claim-updated";
    public static readonly string ClaimUpdatedTopicDescription = "All changes made over a warranty claim.";
}

Topics can be registered using the options API. Nonetheless, we strongly suggest using ITopicConfiguration to keep things clean and sorted.

C#
public class ClaimUpdatedTopicConfiguration : ITopicConfiguration
{
    public void Configure(TopicConfigurator configurator)
    {
        configurator
            .SetName(Topics.ClaimUpdatedTopicName)
            .SetDescription(Topics.ClaimUpdatedTopicDescription)
            .SetTemplate(Templates.ClaimUpdatedTemplateName);
    }
}

Then you can register your topic configuration in the client module

C#
public class MyModule : SuiteModule
{
    public override void SetupModule(IModuleBuilder builder)
    {
        builder.DependsOn<SubscriptionsClientModule, SubscriptionsClientModuleOptions>(
            options => {
                options.RegisterTemplate(
                Templates.ClaimUpdatedTemplateName,
                Templates.ClaimUpdatedTemplatePath,
                Channel.Email);
                options.RegisterTopic<ClaimUpdatedTopicConfiguration>();
            }
        );
    }
}

Sending events to topics

As part of the topic configuration we can define which events will be forwarded to the specified topic when they are published.

C#
public class ClaimUpdatedTopicConfiguration : ITopicConfiguration
{
    public void Configure(TopicConfigurator configurator)
    {
        configurator
            .SetName(Topics.ClaimUpdatedTopicName)
            .SetDescription(Topics.ClaimUpdatedTopicDescription)
            .SetTemplate(Templates.ClaimUpdatedTemplateName)
            .SendWhen<ClaimUpdated>(
                claim => new
                {
                    Claim = new
                    {
                        claim.Code,
                        claim.Subject,
                        claim.CreatedAt,
                        claim.BreakdownDate,
                        claim.DefectedDate,
                    },
                });
    }
}

Note that several events can be sent to a specific topic, this is not a one to one relationship. For example, events related to actions performed over the approval process of an entity could be all bound to the topic

warranty-claims/claim/approvals

To which we could then subscribe to be notified of every change performed to the entity approval status.

A builder callback is also expected so we can specify an object that holds the data required for the template to be rendered properly. The template therefore dictates which fields should be included in this object, and remember: casing matters here.

Ephemeral topics

Sometimes (or most times) subscribers do not want to hear from events on a subject in a general sense, but rather hear from events related to a given piece of information, lets say, a specific claim that is open and being processed.

Ephemeral topics allow you to filter events that correlate with a specific entity if properly configured beforehand: we just need to specify the id field when configuring how the event is sent to the topic.

C#
public class ClaimUpdatedTopicConfiguration : ITopicConfiguration
{
    public void Configure(TopicConfigurator configurator)
    {
        configurator
            .SetName(Topics.ClaimUpdatedTopicName)
            .SetDescription(Topics.ClaimUpdatedTopicDescription)
            .SetTemplate(Templates.ClaimUpdatedTemplateName)
            .SendWhen<ClaimUpdated>(
                message => message.CorrelationId,
                claim => new
                {
                    Claim = new
                    {
                        claim.Code,
                        claim.Subject,
                        claim.CreatedAt,
                        claim.BreakdownDate,
                        claim.DefectedDate,
                    },
                });
    }
}

This allows system users to subscribe to

warranty-claims/claim-updated/0bbe9c76-87d3-490e-a458-b5fea0c33a01

If they want to keep track of a claim with such id.

Binding generic events

Some events in the suite ecosystem are published for more than a single entity or bounded context, usually events that are part of a shared module like workflows or approval ones. If we wanted to subscribe to such event with the known API we would end up receiving events from other services, essentially sending noise to our topics.

To avoid this undesired behavior we can specify that we want to send an event to a topic for only a specific entity:

C#
public class ClaimApprovalTopicConfiguration : ITopicConfiguration
{
    public void Configure(TopicConfigurator configurator)
    {
        configurator
            .SetName(Topics.ClaimApprovalTopicName)
            .SetDescription(Topics.ClaimApprovalTopicDescription)
            .SetTemplate(Templates.ClaimApprovalTemplateName)
            .SendWhen<ApprovalApproved, Claim>(
                message => message.CorrelationId,
                claim => new
                {
                    Claim = new
                    {
                        claim.Code,
                        claim.Subject,
                        claim.CreatedAt,
                        claim.BreakdownDate,
                        claim.DefectedDate,
                    },
                });
    }
}

The specified event is required to implement IHasEntityWellKnownName, since we want to know the entity for which this event was published originally.

Continue reading