1. Home
  2. Docs
  3. Documentation
  4. Plugins
  5. Available server interfaces

Available server interfaces

The server provides a few more interfaces which can be used to make a plugin. These interfaces are already added to the service collection, so they can be used in a plugin constructor.

These interfaces are:

  • IProxyProvider – provides GetProxy methods
  • IRequestContextStore – enables getting the current request context
  • IEventSource – exposes connection events

To demonstrate how these interfaces are used, a new method AddToState is added to the ICalculatorServer interface. This method takes an integer, adds it to internal state, and then broadcasts the message to all users which have previously added to the state.

Method signature added to ICalculatorServer:

[SBMethod(1)]
void AddToState(int increment);

To message all the users that a state change has occurred, a new client plugin is needed. The new interface is named ICalculatorClient and has only one method.

using SB.PluginSDK;

namespace SB.Plugins.Demo.Core
{
    [SBPlugin(11)]
    public interface ICalculatorClient : IPlugin
    {
        [SBMethod(0)]
        void StateUpdated(string updater, int change, int newState, int incrementCounter);
    }
}

Implementation of this plugin on the client is very simple, and only logs:

using SB.Plugins.Demo.Core;
using System;

namespace SB.Plugins.Demo.Client
{
    public class CalculatorClient : ICalculatorClient
    {
        public void StateUpdated(string updater, int change, int newState, int incrementCounter)
        {
            Console.WriteLine(
                $"User {updater} updated the state by {change} to {newState}. " +
                $"Increment Counter: {incrementCounter}");
        }
    }
}

The server implementation is a bit more complex and requires usage of the previously mentioned interfaces available only on the server. AddToState method needs to do the following:

  • Use lock to increment the local state
  • Add the username of the invoker to a local list, to keep for future updates
  • Invoke StateUpdated method on all the clients which have subscribed
  • Unsubscribe users when they are disconnected

Start by adding the interfaces to the plugin constructor, initialize the variables and attach event to the IEventSource:

private readonly IProxyProvider proxyProvider;
private readonly IRequestContextStore contextStore;
private int state;
private int incrementCounter;
private readonly object _incrementLock;

private readonly HashSet<string> subscribedUsers = new HashSet<string>();

public CalculatorServer(
    IProxyProvider proxyProvider,
    IRequestContextStore contextStore,
    IEventSource eventSource)
{
    this.proxyProvider = proxyProvider;
    this.contextStore = contextStore;

    // add event handler
    eventSource.OnClientDisconnected += this.EventSource_OnClientDisconnected;

    this.state = 0;
    this.incrementCounter = 0;

    this._incrementLock = new object();
}

Implement AddToState method:

public void AddToState(int increment)
{
    // calculate the new state
    // note that this method can be executed concurrently from multiple threads
    // therefore, use lock (in cases where only a single value is changed, using Interlocked might be a better choice)

    int newState;
    int incrCounter;
    lock (this._incrementLock)
    {
        this.state += increment;
        this.incrementCounter++;
        newState = this.state;
        incrCounter = this.incrementCounter;
    }

    var username = this.contextStore.Username;

    // add the invoker's username to the subscriber list
    // so the user will be notified of any state changes
    subscribedUsers.Add(username);

    // get proxy to invoke ICalculatorClient.StateUpdated method on all users that added to the state
    // since the method is going to be invoked on multiple users, it is possible only to use FireAndForget method call style
    // note that, in this example we use Linq ToArray - but you should not use Linq in your high performance systems
    var proxy = this.proxyProvider.GetProxy<ICalculatorClient>(this.subscribedUsers.ToArray());

    // invoke the method on subscribed users
    proxy.StateUpdated(username, increment, newState, incrCounter);
}

And finally, implement the OnClientDisconnected event handler, so the disconnected users are removed from the local subscriber list:

private void EventSource_OnClientDisconnected()
{
    var username = this.contextStore.Username;
    // user disconnected - remove him from the subscriber list
    this.subscribedUsers.Remove(username);
}

To summarize:

  • IProxyProvider – provides GetProxy methods
  • IRequestContextStore – enables getting the current request context, the most common use is to get the invoker’s username
  • IEventSource – allows the plugin to subscribe to client connect and disconnect events

Next step: Server configuration.

Was this article helpful to you? Yes No

How can we help?