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.

  • Triger - action of the (string Message, bool IsCancelled) TriggerAction (EntityModel model, List<dynamic> entities, 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, returnes a filter that is applied to the query.
  • Action - action of the dynamic Action (dynamic request) type - a server method of business logic. This functionality will soon be implemented.

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>, dynamic, (string Message, bool IsCancelled)>> _triggers
        = new Dictionary<string, Func<EntityModel, List<dynamic>, dynamic, (string Message, bool IsCancelled)>>();

    private Dictionary<string, Func<EntityModel, List<dynamic>, dynamic, Task<(string Message, bool IsCancelled)>>> _triggersAsync
        = new Dictionary<string, Func<EntityModel, List<dynamic>, dynamic, Task<(string Message, bool IsCancelled)>>>();

    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 (string Message, bool IsCancelled) ExecuteTrigger(string name, EntityModel model, List<dynamic> entities, dynamic options)
    {
        if (_triggers.ContainsKey(name))
            return _triggers[name](model, entities, options);
        throw new NotImplementedException();
    }

    public Task<(string Message, bool IsCancelled)> ExecuteTriggerAsync(string name, EntityModel model, List<dynamic> entities, dynamic options)
    {
        if (_triggersAsync.ContainsKey(name))
            return _triggersAsync[name](model, entities, options);
        throw new 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 dynamic ExecuteAction(string name, dynamic request)
    {
        if (_actions.ContainsKey(name))
            return _actions[name](request);
        throw new NotImplementedException();
    }

    public async Task<dynamic> 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<(string Message, bool IsCancelled)> CustomAsyncTrigger(EntityModel model, List<object> entities, dynamic options)
    {
        return (string.Empty, false);
    }

    private (string Message, bool IsCancelled) CustomTrigger(EntityModel model, List<object> entities, dynamic options)
    {
        return (string.Empty, false);
    }

    #endregion

    #region Actions

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

    private dynamic CustomAction(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 givenname` 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 http://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.