Actions in Objects and Managers

Actions in the system architecture

For any operations with objects, you need to create managers inherited from EntityManager. In these managers, different actions are defined as public methods:

/// <summary>
/// Block user’s account
/// </summary>
/// <param name="user">User</param>
public void Block(Models.IUser user)

When you call a method, you need to check if it can be completed and handle possible exceptions. Often methods can be completed only if you have appropriate access permissions – you need to take this into account too. To avoid double-checks and allow calling the methods from anywhere in ELMA (e.g. scripts, web application, external systems), you need to work with objects using their actions.

How to create an action for an entity

You can add an action to an object using the entity editor either in ELMA Designer or in Visual Studio. To do it, go to Object pageActions tab and add a new action:

After the model is saved, a set of action keys is generated for the entity. In our case, the following code will be generated:

/// <summary>
    /// Actions for "MyCompany" object
    /// </summary>
    public class MyCompanyActions : EleWise.ELMA.Model.Actions.DefaultEntityActions
    {
        
        /// <summary>
        /// Replace
        /// </summary>
        [global::EleWise.ELMA.Model.Attributes.Uid("3c0cd537-8950-46f9-b8f7-de9dd9e0a773")]
        [global::EleWise.ELMA.Model.Attributes.DisplayName(typeof(@__Resources_MyCompanyActions), "P_Replace_DisplayName")]
        public const string Replace = "3c0cd537-8950-46f9-b8f7-de9dd9e0a773";
        
        private static global::System.Guid _replaceGuid = new System.Guid(Replace);
        
        protected MyCompanyActions()
        {
        }
        
        /// <summary>
        /// Replace
        /// </summary>
        public static global::System.Guid ReplaceGuid
        {
            get
            {
                return _replaceGuid;
            }
        }
    }
    
    internal class @__Resources_MyCompanyActions
    {
        
        public static string DisplayName
        {
            get
            {
                return global::EleWise.ELMA.SR.T("Actions for \"MyCompany\" object");
            }
        }
        
        public static string P_Replace_DisplayName
        {
            get
            {
                return global::EleWise.ELMA.SR.T("Replace");
            }
        }
    }

These keys on their own have no logic - you define it in the methods of entity managers. To show that a method implements an action, you need to mark this method with EleWise.ELMA.Actions.ActionMethodAttribute.

In our case, we will do it as follows:

/// <summary>
/// Block user’s account
/// </summary>
/// <param name="user">User</param>
[EleWise.ELMA.Actions.ActionMethod(UserActions.Block)]
public virtual void Block(Models.IUser user)
{
    //Only action’s code without checks
}

Note that the method is marked as virtual and public – you need to do this to ensure that it will work properly.

However, this is not enough. We also need to define the access permissions and other criteria required for completing the action.

To define the access permission for our action, we need to mark it with the EleWise.ELMA.Actions.ActionPermissionAttribute:

/// <summary>
/// Block user's account
/// </summary>
/// <param name="user">User</param>
[EleWise.ELMA.Actions.ActionMethod(UserActions.Block)]
[ActionPermission(PermissionProvider.UserManagmentPermissionId)]
public virtual void Block(Models.IUser user)

You define the set of permissions when you create a module. In our case, we defined that only users with Users Administration permission can block users.

Then you need to check if the user that you want to block is active and make sure that it is not the administrator’s account. For that, you need to create another method with an exactly the same set of parameters. This method will return the bool value. We also need to mark this method with EleWise.ELMA.Actions.ActionCheckAttribute and specify the same action as we did for the main (Block) method.

/// <summary>
/// Check if we can execute the action
/// </summary>
/// <param name="user">User</param>
/// <returns><c>true</c>, if the action can be executed</returns>
[EleWise.ELMA.Actions.ActionCheck(UserActions.Block)]
protected virtual bool CanBlock(Models.IUser user)
{
    return user != null && !IsNew(user) && user.Status == UserStatus.Active && user.UserName != "admin";
}

Just as the main method, this method must be marked as virtual and public/protected.
Now when we call the UserManager.Instance.Block(user) method, ELMA will check if the executor has appropriate access permissions first, then CanBlock method will be called to check if additional criteria are met, and only after that ELMA will execute the action.

Use ELMA services to work with actions

There is a special service for managing actions, EleWise.ELMA.Actions.ActionDispatcherService. It has two methods that we need:

/// <summary>
/// Check if action can be executed 
/// You do not need to call it before execution
/// </summary>
/// <param name="actionObject">Action object</param>
/// <param name="actionType">Action type</param>
/// <param name="methodArgs">Arguments sent to the action</param>
/// <returns>If the action can be executed in this context</returns>
public bool CheckAction(IAuditObject actionObject, IAuditAction actionType, params object[] methodArgs)
 
/// <summary>
/// Execute action (verification will be performed)
/// </summary>
/// <param name="actionType">Action type</param>
/// <param name="actionObject">Action object</param>
/// <param name="methodArgs"> Arguments sent to the action </param>
/// <returns>Action execution result</returns>
/// <exception cref="System.InvalidOperationException">If CheckAction returns false</exception>
public object InvokeAction(IAuditObject actionObject, IAuditAction actionType, params object[] methodArgs)

As you can see, the examples above use objects of the IAuditObject and IAuditAction types. These objects link the actions and events in such a way, that these actions can be executed for any object or event in ELMA.

You can learn more about EleWise.ELMA.Actions.ActionDispatcherService in ELMA API help.

Links to API elements

ActionDispatcherService