Marketplace
latest
false
Banner background image
Marketplace User Guide
Last updated Feb 28, 2024

The Activity File

Important: This document refers to a deprecated version of the UiPath Activity Creator for Visual Studio. Please see the new documentation here.

Intro

Every activity begins with an Activity class file that defines its inputs, outputs, and execution logic. To better understand how this is done, open the ChildActivity.cs file in your Activity project and walk through it section by section. This is a simple activity that adds two numbers together and outputs their sum.



using System;
using System.Activities;
using System.Threading;
using System.Threading.Tasks;
using MyCompany.MyProduct.Activities.Properties;
using UiPath.Shared.Activities;
namespace MyCompany.MyProduct.Activities
{
    [LocalizedDisplayName(nameof(Resources.ChildActivityDisplayName))]
    [LocalizedDescription(nameof(Resources.ChildActivityDescription))]
    public class ChildActivity : AsyncTaskCodeActivity
    {
        #region Properties
        [LocalizedDisplayName(nameof(Resources.ChildActivityFirstNumberDisplayName))]
        [LocalizedDescription(nameof(Resources.ChildActivityFirstNumberDescription))]
        [LocalizedCategory(nameof(Resources.Input))]
        public InArgument<int> FirstNumber { get; set; }
        [LocalizedDisplayName(nameof(Resources.ChildActivitySecondNumberDisplayName))]
        [LocalizedDescription(nameof(Resources.ChildActivitySecondNumberDescription))]
        [LocalizedCategory(nameof(Resources.Input))]
        public InArgument<int> SecondNumber { get; set; }
        [LocalizedDisplayName(nameof(Resources.ChildActivitySumDisplayName))]
        [LocalizedDescription(nameof(Resources.ChildActivitySumDescription))]
        [LocalizedCategory(nameof(Resources.Output))]
        public OutArgument<string> Sum { get; set; }
        #endregion
          
        #region Constructors
          
        public ChildActivity()
        {
              Constraints.Add(ActivityConstraints.HasParentType<ChildActivity, ParentScope>(Resources.ValidationMessage));
        }
      
        #endregion
          
        #region Protected Methods
        protected override void CacheMetadata(CodeActivityMetadata metadata)
        {
              if (FirstNumber == null) metadata.AddValidationError(string.Format(Resources.MetadataValidationError, nameof(FirstNumber)));
              if (SecondNumber == null) metadata.AddValidationError(string.Format(Resources.MetadataValidationError, nameof(SecondNumber)));
              base.CacheMetadata(metadata);
        }
        protected override async Task<Action<AsyncCodeActivityContext>> ExecuteAsync(AsyncCodeActivityContext context, CancellationToken cancellationToken)
        {
              var property = context.DataContext.GetProperties()[ParentScope.ApplicationTag];
              var app = property.GetValue(context.DataContext) as Application;
           
              var firstValue = FirstNumber.Get(context);
              var secondValue = SecondNumber.Get(context);
        
              var sum = app.Sum(firstValue, secondValue);
              return ctx =>
              {
                  Sum.Set(ctx, sum);
              };
       }
        #endregion
    }
}using System;
using System.Activities;
using System.Threading;
using System.Threading.Tasks;
using MyCompany.MyProduct.Activities.Properties;
using UiPath.Shared.Activities;
namespace MyCompany.MyProduct.Activities
{
    [LocalizedDisplayName(nameof(Resources.ChildActivityDisplayName))]
    [LocalizedDescription(nameof(Resources.ChildActivityDescription))]
    public class ChildActivity : AsyncTaskCodeActivity
    {
        #region Properties
        [LocalizedDisplayName(nameof(Resources.ChildActivityFirstNumberDisplayName))]
        [LocalizedDescription(nameof(Resources.ChildActivityFirstNumberDescription))]
        [LocalizedCategory(nameof(Resources.Input))]
        public InArgument<int> FirstNumber { get; set; }
        [LocalizedDisplayName(nameof(Resources.ChildActivitySecondNumberDisplayName))]
        [LocalizedDescription(nameof(Resources.ChildActivitySecondNumberDescription))]
        [LocalizedCategory(nameof(Resources.Input))]
        public InArgument<int> SecondNumber { get; set; }
        [LocalizedDisplayName(nameof(Resources.ChildActivitySumDisplayName))]
        [LocalizedDescription(nameof(Resources.ChildActivitySumDescription))]
        [LocalizedCategory(nameof(Resources.Output))]
        public OutArgument<string> Sum { get; set; }
        #endregion
          
        #region Constructors
          
        public ChildActivity()
        {
              Constraints.Add(ActivityConstraints.HasParentType<ChildActivity, ParentScope>(Resources.ValidationMessage));
        }
      
        #endregion
          
        #region Protected Methods
        protected override void CacheMetadata(CodeActivityMetadata metadata)
        {
              if (FirstNumber == null) metadata.AddValidationError(string.Format(Resources.MetadataValidationError, nameof(FirstNumber)));
              if (SecondNumber == null) metadata.AddValidationError(string.Format(Resources.MetadataValidationError, nameof(SecondNumber)));
              base.CacheMetadata(metadata);
        }
        protected override async Task<Action<AsyncCodeActivityContext>> ExecuteAsync(AsyncCodeActivityContext context, CancellationToken cancellationToken)
        {
              var property = context.DataContext.GetProperties()[ParentScope.ApplicationTag];
              var app = property.GetValue(context.DataContext) as Application;
           
              var firstValue = FirstNumber.Get(context);
              var secondValue = SecondNumber.Get(context);
        
              var sum = app.Sum(firstValue, secondValue);
              return ctx =>
              {
                  Sum.Set(ctx, sum);
              };
       }
        #endregion
    }
}

Imports and Namespace

The file starts with standard boilerplate. It imports some namespaces and then declares that this activity will itself live in the MyCompany.MyProduct.Activities namespace.

using System;
using System.Activities;
using System.Threading;
using System.Threading.Tasks;
using MyCompany.MyProduct.Activities.Properties;
using UiPath.Shared.Activities;
namespace MyCompany.MyProduct.Activities
{using System;
using System.Activities;
using System.Threading;
using System.Threading.Tasks;
using MyCompany.MyProduct.Activities.Properties;
using UiPath.Shared.Activities;
namespace MyCompany.MyProduct.Activities
{

Class Definition

All standard activity classes (such as the sample ChildActivity) extend AsyncTaskCodeActivity, which provides methods for design-time validation of properties and run-time execution logic, and can be found in the Shared folder included in your solution. Additionally, all activities that extend AsyncTaskCodeActivity may run asynchronously, allowing them to be used with the Parallel and Parallel For Each activities in UiPath Studio.
[LocalizedDisplayName(nameof(Resources.ChildActivityDisplayName))]
[LocalizedDescription(nameof(Resources.ChildActivityDescription))]
public class ChildActivity : AsyncTaskCodeActivity
{[LocalizedDisplayName(nameof(Resources.ChildActivityDisplayName))]
[LocalizedDescription(nameof(Resources.ChildActivityDescription))]
public class ChildActivity : AsyncTaskCodeActivity
{
Above the ChildActivity class definition, you'll notice two attributes--LocalizedDisplayName and LocalizedDescription. These allow you to set the name and tooltip description of the activity that appear in UiPath Studio's activities pane. In this example, the attributes reference localized versions of each (e.g. Resources.ChildActivityDisplayName), but simple strings may be used as well. For more information on localization, see here.




Properties

Next are the activity's properties, which appear in the Properties Pane of UiPath Studio. Each property has a display name and description as the top-level activity did, but also included is a Category attribute to help group related activities. Notice how FirstNumber and SecondNumber appear in the Input category, but Sum appears under Output.
[LocalizedDisplayName(nameof(Resources.ChildActivityFirstNumberDisplayName))]
[LocalizedDescription(nameof(Resources.ChildActivityFirstNumberDescription))]
[LocalizedCategory(nameof(Resources.Input))]
public InArgument<int> FirstNumber { get; set; }
[LocalizedDisplayName(nameof(Resources.ChildActivitySecondNumberDisplayName))]
[LocalizedDescription(nameof(Resources.ChildActivitySecondNumberDescription))]
[LocalizedCategory(nameof(Resources.Input))]
public InArgument<int> SecondNumber { get; set; }
[LocalizedDisplayName(nameof(Resources.ChildActivitySumDisplayName))]
[LocalizedDescription(nameof(Resources.ChildActivitySumDescription))]
[LocalizedCategory(nameof(Resources.Output))]
public OutArgument<int> Sum { get; set; }[LocalizedDisplayName(nameof(Resources.ChildActivityFirstNumberDisplayName))]
[LocalizedDescription(nameof(Resources.ChildActivityFirstNumberDescription))]
[LocalizedCategory(nameof(Resources.Input))]
public InArgument<int> FirstNumber { get; set; }
[LocalizedDisplayName(nameof(Resources.ChildActivitySecondNumberDisplayName))]
[LocalizedDescription(nameof(Resources.ChildActivitySecondNumberDescription))]
[LocalizedCategory(nameof(Resources.Input))]
public InArgument<int> SecondNumber { get; set; }
[LocalizedDisplayName(nameof(Resources.ChildActivitySumDisplayName))]
[LocalizedDescription(nameof(Resources.ChildActivitySumDescription))]
[LocalizedCategory(nameof(Resources.Output))]
public OutArgument<int> Sum { get; set; }


Properties may be declared as type InArgument, InOutArgument, or OutArgument and must indicate their expected type (e.g. string, int, ...).

Constructor

public ChildActivity()
{
     FirstNumber = 10;
     Constraints.Add(ActivityConstraints.HasParentType<ChildActivity, ParentScope>(Resources.ValidationMessage));
}public ChildActivity()
{
     FirstNumber = 10;
     Constraints.Add(ActivityConstraints.HasParentType<ChildActivity, ParentScope>(Resources.ValidationMessage));
}

The constructor is used to set default values and constraints on properties.

  • In the example above, the FirstNumber property is given a default value of 10, which appears in the Properties Pane.


  • Additionally, a constraint is placed on the activity itself, requiring that it be surrounded by a ParentScope. If it is not, a validation error is shown.



CacheMetadata

CacheMetadata provides validation of an activity's properties, delegates, and/or child activities. In this example, we check that values have been provided for the two input properties, FirstNumber and SecondNumber, and throw a validation error if either is not provided. Until the validation errors are handled, a workflow will not run.
protected override void CacheMetadata(CodeActivityMetadata metadata)
{
    if (FirstNumber == null) metadata.AddValidationError(string.Format(Resources.MetadataValidationError, nameof(FirstNumber)));
    if (SecondNumber == null) metadata.AddValidationError(string.Format(Resources.MetadataValidationError, nameof(SecondNumber)));
    base.CacheMetadata(metadata);
}protected override void CacheMetadata(CodeActivityMetadata metadata)
{
    if (FirstNumber == null) metadata.AddValidationError(string.Format(Resources.MetadataValidationError, nameof(FirstNumber)));
    if (SecondNumber == null) metadata.AddValidationError(string.Format(Resources.MetadataValidationError, nameof(SecondNumber)));
    base.CacheMetadata(metadata);
}


ExecuteAsync

ExecuteAsync is where the execution logic of the activity is held.

  • The first two lines of the method query the activity context--or the current state of the ChildActivity and the elements surrounding it--to retrieve an Application object from the ParentScope if one surrounds it. Note that, because of the constraint added in the constructor above, this activity will never be allowed to run if it is not already in a ParentScope.
  • The next lines take the current values of the FirstNumber and SecondNumber properties and save them to local variables.
  • The last lines perform a Sum operation on the inputted numbers and set the Sum property to this value. Because Sum is an output property, this value may then be used by subsequent activities in the workflow.
    protected override async Task<Action<AsyncCodeActivityContext>> ExecuteAsync(AsyncCodeActivityContext context, CancellationToken cancellationToken)
    {
        var property = context.DataContext.GetProperties()[ParentScope.ApplicationTag];
        var app = property.GetValue(context.DataContext) as Application;
               
        var firstValue = FirstNumber.Get(context);
        var secondValue = SecondNumber.Get(context);
            
        var sum = app.Sum(firstValue, secondValue);
        return ctx =>
        {
            Sum.Set(ctx, sum);
        };
    }protected override async Task<Action<AsyncCodeActivityContext>> ExecuteAsync(AsyncCodeActivityContext context, CancellationToken cancellationToken)
    {
        var property = context.DataContext.GetProperties()[ParentScope.ApplicationTag];
        var app = property.GetValue(context.DataContext) as Application;
               
        var firstValue = FirstNumber.Get(context);
        var secondValue = SecondNumber.Get(context);
            
        var sum = app.Sum(firstValue, secondValue);
        return ctx =>
        {
            Sum.Set(ctx, sum);
        };
    }
    Important:
    Notice that the ExecuteAsync method returns a Task<Action<AsyncCodeActivityContext>> object.
    A Task is returned so this activity can run asynchronously.
    An Action is returned within this Task in order to allow for complex functions to be executed after any asynchronous operations have completed. In the example above, this function simply sets the value of Sum.
    Lastly, the Action takes an AsyncCodeActivityContext parameter so the context from this activity may be used by any such functions running after the asynchronous operations have finished. If this was not the case, the context could be lost and the Sum would not be easily modifiable.

Was this page helpful?

Get The Help You Need
Learning RPA - Automation Courses
UiPath Community Forum
Uipath Logo White
Trust and Security
© 2005-2024 UiPath. All rights reserved.