- Release notes
- Overview
- Getting started
- Marketplace Vendors
- Marketplace Customers
- Publishing Guidelines
- Publishing Guidelines for Ready-to-go Automations
- Publishing Guidelines for Solution Accelerators
- Publishing Guidelines for Integration Service Connectors
- Publishing Guidelines for Process Mining app templates
- Security & IP Protection
- Other UiPath Listings
- Node-RED
- Setup
- Teams
- Microsoft Teams scope
- Create team
- Create team from group
- Get team
- Get teams
- Channels
- Create channel
- Delete channel
- Get channel
- Get channels
- Update channel
- Chats
- Get chat
- Get chats
- Get chat members
- Messages
- Get message
- Get messages
- Get message replies
- Reply to message
- Send message
- Events
- Create event
- Delete event
- Get event
- Get events
- Users
- Get user presence
- How it works
- Technical references
- Get started
- About
- Setup
- Technical references
- Azure Form Recognizer scope
- Activities
- Analyze form
- Analyze form async
- Get analyze form result
- Analyze receipt
- Analyze receipt async
- Get analyze receipt result
- Analyze layout
- Analyze layout async
- Get analyze layout result
- Train model
- Get models
- Get model keys
- Get model info
- Delete model
- Connectors
- How to create activities
- Build Your Integration

Marketplace user guide
The activity file
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
FirstNumberproperty 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
Applicationobject 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
FirstNumberandSecondNumberproperties and save them to local variables. -
The last lines perform a Sum operation on the inputted numbers and set the
Sumproperty to this value. BecauseSumis 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. ATaskis returned so this activity can run asynchronously. AnActionis 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 ofSum. Lastly, theActiontakes anAsyncCodeActivityContextparameter 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 theSumwould not be easily modifiable.