Using actions.

Why is it important? Real life example

For example you've got a certain component in your app, and a certain event in this component initiates client actions chain execution. Thus Save&Exit button for the onClick event initiates the next validate,save,exit chain. There are cases when after saving the document you want to send an e-mail to certain users or call another server code. It means that your chain will look something like that: validate,save,notify,exit. It is important that the code is executed on the server and its execution is initiated from the client. Of course, you can modify the DataController.ChangeData() method or write your own controller, call it from the client using fetch, and process the response yourself. But first method is clearly defective, and the second one presumes routine manual coding. In contrast DWKit is a simple and unified mechanism of writing server methods in order to select their names from the drop-down list as shown in the picture below.

Actions

Signature

DWKit server Action is a function receiving dynamic and returning object. I.e. it is the simplest type of server functions. And it is most essential that DWKit can call such functions directly in the chain of actions which handle events from form components. But you can always call them manually from any javascript code.

There are two types of action signature:

  • Synchronous action
    public object SyncAction(dynamic request)
    {
    ...
    }
  • Asynchronous action
    public async Task<object> AsyncAction(dynamic request)
    {
    ...
    }

    If synchronous methods are called in action, use synchronous actions. For asynchronous methods use asynchronous actions.

There is only one dynamic parameter in Server Action. What this parameter contains depends on how this Server Action was called. There are two types of calls: call from the chain of actions of event handlers and custom call. Server Action returns object, which is interpreted in a definite way. Let's see how it happens.

Server Action call from the handlers chain

If you have added server Action to IServerActionsProvider implementation or in the CodeActions section in the admin panel, you can immediately include it into event handlers of any component. See picture in the beginning of this section. When using this type of call the server will receive as an input action parameter (dynamic request) a ServerCodeActionRequest object with the following properties:

  • public string FormName - name of the form in events of which this action is called
  • public DynamicEntity Data - form data
  • public dynamic Parameters - parameters, with which client actions are called in the chain. See next picture.

Actions setup

Thus, if your server Action is called in the chain of client Actions, you can always work with the request parameter as with an object of the ServerCodeActionRequest type. For example:

public object SyncAction(dynamic request)
{
    var typedRequest = request as ServerCodeActionRequest;
    var data = typedRequest.Data;
    ...
}

Server Action custom call

There are two functions in DWKit Global client API, using which you can call server Actions from any javascript code. For this use the following two functions. Full list of their parameters and using methods can be found here:

  • return callServerCodeAction(name, request, callback) - returns delta for global state of the client application; it is used mainly inside another client action, which is called in the chain. It must be used with return statement.
  • callServerCodeActionDispatch(name, request, callback) - immediately applies value returned from the server to the global state of the client application. Can be used in any javascript code.

Despite the fact that we've got two functions, parameters with which they are called are absolutely identical in use.

  • name - name by which DWKit searches for Server Action.
  • request - is an object which will be transmitted to server Action as the (dynamic request) parameter.

Let's see in more detail how request object is transferred from the server to the client. Suppose you've got the following javascript code:

someClientAction: function (args) {
    var request = {
        name : "Name",
        value : 100
    };
    //return value style
    return DWKitApp.API.callServerCodeAction("ServerActionName", request);
    //OR
    // immediate dispatch style
    DWKitApp.API.callServerCodeActionDispatch("ServerActionName", request);
}

Then name and value values on the server can be received by the following method:

public object ServerActionName(dynamic request)
{
    var name = request.name; //will be string "Name"
    var value = request.value; //will be integer 100 
    return new {
        ...
    };
}

Server Action returning value interpretation

Despite the fact that we've got two server Actions call types, their returning value is always interpreted by DWKit client-side in the same way. It means that returning value interpretation does not depend on the call type. Here are all possible methods to return values from server Action:

  • return null; - means that action was completed successfully, there no changes to the client side of DWKit application. If server Action is called in the chain, the chain will be continued.
  • throw new Exception(message); - action will be completed with an error which will be displayed in the client as a pop-up message and stacktrace exception record in the browser console. If server Action is called in the chain, the chain will be interrupted.
  • return new {...} - returning an object of anonymous type; can be interpreted differently depending whether there are stateDelta and data properties in the object.

    • if there is a stateDelta property in the returning object, which is an object of anonymous type in itself, it will be applied to the global state of the client application. Actually you can manage client state from Server Actions the same way you do it via SignalR. For example, let's change inbox, total and outbox counts in the client:
    public object ServerActionName(dynamic request)
    {
        ...
        return new {
            stateDelta = new {
                app = new {
                    extra = new {
                        inbox = 40,
                        outbox = 10,
                        total = 50
                    }
                }
            }
        };
    }
    • if there is a data property in the returning object which can be an object of anonymous type or a DynamicObject object, it will be transmitted to further actions in the chain as a data parameter. Below you will see an example of its use. Please note that if the Server Action is called outside the chain of actions, this value will be disregarded.
    • if there are simultaneously stateDelta and data properties in the returning object, both mechanism described above will be applied.
    • if there is neither stateDelta nor data property in the returning object, returning value will be applied to the global state of the client application. I.e. the following code
    public object ServerActionName(dynamic request)
    {
        ...
        return new {
            app = new {
                ...
            }
        };
    }

    will work similar to

    public object ServerActionName(dynamic request)
    {
        ...
        return new {
            stateDelta = new {
                app = new {
                   ...
                }
            }
        };
    }
    
  • DynamicObject object is returned. Usually it's form data. I.e. you can change form data in server Action called in the chain, which is launched upon event from the form component, and send them to the client. In further actions in the chain you can use changed data via data parameter, which is transmitted to each client action. For example, if after calling server Action there will be save action in the chain (not necessarily straight away), changed data will be saved. Such code will look the following in the server:
public object ServerActionName(dynamic request)
{
    var typedRequest = request as ServerCodeActionRequest;
    var data = typedRequest.Data;
    data.amount = data.amount * 10; //increase document amount in ten times
    return data;
}

CodeActionController behaviour customization

Server Actions call and their parameters handling logic is in CodeActionController. Here's its code on GitHub. You can see that the code is very simple and comprehensible. If you need complex behaviour customization of the Server Actions mechanism, just write your controller which will launch such actions and interpret input parameters and returning value.