Server user-defined actions

In DWKit, you can write special actions that will be executed upon changing or requesting data via the DWKit ORM. They come in three types.

  • Trigger - action of the TriggerResult TriggerAction (EntityModel model, List<dynamic> entities, TriggerExecutionContext context, dynamic options) type, called before or after changing (insert, update, delete) or after select. You can amend a set of saved or returned data, enable calling of business logic, or cancel the entire operation in the triggers.
  • Filter - action of the Filter FilterAction (EntityModel model, List<dynamic> entities, dynamic options) type, returns a filter that is applied to the query.
  • Action - action of the object Action (dynamic request) type - a server method of business logic.

You can create Server user-defined Actions both in the admin application and in the code of your application, creating classes implementing the IServerActionsProvider interface. Below is an example, which you can copy and paste into your application.

public class ActionsProvider : IServerActionsProvider
{
    private Dictionary<string, Func<EntityModel, List<dynamic>, dynamic, Filter>> _filters
        = new Dictionary<string, Func<EntityModel, List<dynamic>, dynamic, Filter>>();

    private Dictionary<string, Func<EntityModel, List<dynamic>, dynamic, Task<Filter>>> _filtersAsync
        = new Dictionary<string, Func<EntityModel, List<dynamic>, dynamic, Task<Filter>>>();

    private Dictionary<string, Func<EntityModel, List<dynamic>, TriggerExecutionContext, dynamic,  TriggerResult>> _triggers
            = new Dictionary<string, Func<EntityModel, List<dynamic>,TriggerExecutionContext, dynamic,TriggerResult>>();

    private Dictionary<string, Func<EntityModel, List<dynamic>,TriggerExecutionContext, dynamic, Task<TriggerResult>>> _triggersAsync
            = new Dictionary<string, Func<EntityModel, List<dynamic>,TriggerExecutionContext, dynamic, Task<TriggerResult>>>();

    private Dictionary<string, Func<dynamic, dynamic>> _actions
        = new Dictionary<string, Func<dynamic, dynamic>>();

    private Dictionary<string, Func<dynamic, Task<dynamic>>> _actionsAsync
        = new Dictionary<string, Func<dynamic, Task<dynamic>>>();

    #region IServerActionsProvider implementation

    public List<string> GetFilterNames()
    {
        return _filters.Keys.Concat(_filtersAsync.Keys).ToList();
    }

    public bool IsFilterAsync(string name)
    {
        return _filtersAsync.ContainsKey(name);
    }

    public bool ContainsFilter(string name)
    {
        return _filtersAsync.ContainsKey(name) || _filters.ContainsKey(name);
    }

    public Filter GetFilter(string name, EntityModel model, List<dynamic> entities, dynamic options)
    {
        if (_filters.ContainsKey(name))
            return _filters[name](model, entities, options);
        throw new NotImplementedException();
    }

    public Task<Filter> GetFilterAsync(string name, EntityModel model, List<dynamic> entities, dynamic options)
    {
        if (_filtersAsync.ContainsKey(name))
            return _filtersAsync[name](model, entities, options);
        throw new NotImplementedException();
    }

    public List<string> GetTriggerNames()
    {
        return _triggers.Keys.Concat(_triggersAsync.Keys).ToList();
    }

    public bool IsTriggerAsync(string name)
    {
        return _triggersAsync.ContainsKey(name);
    }

    public bool ContainsTrigger(string name)
    {
        return _triggersAsync.ContainsKey(name) || _triggers.ContainsKey(name);
    }

    public TriggerResult ExecuteTrigger(string name, EntityModel model, List<dynamic> entities,TriggerExecutionContext context, dynamic options)
    {
        if (_triggers.ContainsKey(name))
            return _triggers[name](model, entities,context, options);
        throw new System.NotImplementedException();
    }

    public Task<TriggerResult> ExecuteTriggerAsync(string name, EntityModel model, List<dynamic> entities, TriggerExecutionContext context, dynamic options)
    {
        if (_triggersAsync.ContainsKey(name))
            return _triggersAsync[name](model, entities, context, options);
        throw new System.NotImplementedException();
    }

    public List<string> GetActionNames()
    {
        return _actions.Keys.Concat(_actionsAsync.Keys).ToList();
    }

    public bool IsActionAsync(string name)
    {
        return _actionsAsync.ContainsKey(name);
    }

    public bool ContainsAction(string name)
    {
        return _actions.ContainsKey(name) || _actionsAsync.ContainsKey(name);
    }

    public object ExecuteAction(string name, dynamic request)
    {
        if (_actions.ContainsKey(name))
            return _actions[name](request);
        throw new NotImplementedException();
    }

    public async Task<object> ExecuteActionAsync(string name, dynamic request)
    {
        if (_actionsAsync.ContainsKey(name))
            return _actionsAsync[name](request);
        throw new NotImplementedException();
    }

    #endregion

    public ActionsProvider()
    {
        _filtersAsync.Add("CustomAsyncFilter", CustomAsyncFilter);
        _filters.Add("CustomFilter", CustomFilter);

        _triggersAsync.Add("CustomAsyncTrigger", CustomAsyncTrigger);
        _triggers.Add("CustomTrigger", CustomTrigger);

        _actionsAsync.Add("CustomAsyncAction", CustomAsyncAction);
        _actions.Add("CustomAction", CustomAction);
    }

    #region Filters

    private async Task<Filter> CustomAsyncFilter(EntityModel model, List<object> entities, dynamic options)
    {
        return Filter.Empty;
    }

    private Filter CustomFilter(EntityModel model, List<object> entities, dynamic options)
    {
        return Filter.Empty;
    }

    #endregion

    #region Triggers

    private async Task<TriggerResult> CustomAsyncTrigger(EntityModel model, List<object> entities, TriggerExecutionContext context, dynamic options)
    {
        return TriggerResult.Success();
    }

    private TriggerResult CustomTrigger(EntityModel model, List<object> entities, TriggerExecutionContext context, dynamic options)
    {
        return TriggerResult.Success();
    }

    #endregion

    #region Actions

    private async Task<object> CustomAsyncAction(dynamic request)
    {
        return null;
    }

    private Task<object> CustomAsyncAction(dynamic request)
    {
        return null;
    }

    #endregion

}

Triggers, Filters and Actions work in a similar way here. The Get***Names functions return the lists of the Triggers, Filters or Actions names to be displayed in the admin panel. The Is***Async functions return true if Trigger, Filter or Action must be executed asynchronously. The Contains*** functions check whether Trigger, Filter or Action is contained in the action provider.

The GetFilter and GetFilterAsync functions return filters with the given name name. The ExecuteTrigger and ExecuteTriggerAsync functions execute a trigger with the given name name. The ExecuteAction and ExecuteActionAsync functions execute an action with the given name name.

After ActionsProvider is created, you should register it in DWKitRuntime.

DWKitRuntime.ServerActions.RegisterUsersProvider("provider", new ActionsProvider());

The connection between the EntityModel model and the Triggers, Filters or Actions calling can be adjusted in the admin. For example, Triggers can be specified in the Triggers section. Filters are specified in the url so far. For example, if you open the https://demo.dwkit.com/form/documents/outbox page, DWKit will decipher this url as - formName = "documents", filter="outbox" and try to call a user-defined action of the filter type with the "outbox" name. Other ways of application will be introduced in the coming release versions.