< Summary

Line coverage
83%
Covered lines: 255
Uncovered lines: 51
Coverable lines: 306
Total lines: 979
Line coverage: 83.3%
Branch coverage
83%
Covered branches: 88
Total branches: 106
Branch coverage: 83%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
File 1: CanCancelActivity()100%22100%
File 1: CancelActivityAsync()50%2290%
File 1: CancelChildActivitiesAsync()50%2266.66%
File 2: CompleteActivityAsync()75%131281.81%
File 2: CompleteActivityWithOutcomesAsync(...)100%11100%
File 2: CompleteCompositeAsync()100%210%
File 3: .ctor(...)100%44100%
File 3: get_Id()100%11100%
File 3: get_StartedAt()100%11100%
File 3: get_Tag()100%11100%
File 3: get_CompletedAt()100%11100%
File 3: get_IsCompleted()100%22100%
File 3: get_IsExecuting()100%11100%
File 3: get_AggregateFaultCount()100%11100%
File 3: get_WorkflowExecutionContext()100%11100%
File 3: get_ParentActivityExecutionContext()100%11100%
File 3: set_ParentActivityExecutionContext(...)100%22100%
File 3: get_SchedulingActivityExecutionId()100%11100%
File 3: get_SchedulingActivityId()100%11100%
File 3: get_SchedulingWorkflowInstanceId()100%11100%
File 3: get_CallStackDepth()100%11100%
File 3: get_ExpressionExecutionContext()100%11100%
File 3: get_Variables()83.33%1212100%
File 3: get_DynamicVariables()100%11100%
File 3: get_Activity()100%11100%
File 3: get_ActivityDescriptor()100%11100%
File 3: get_CancellationToken()100%11100%
File 3: get_Status()100%11100%
File 3: set_Status(...)100%22100%
File 3: EnterExecution()100%11100%
File 3: TransitionTo(...)100%11100%
File 3: get_Exception()100%11100%
File 3: set_Exception(...)100%11100%
File 3: get_Properties()100%11100%
File 3: get_TransientProperties()100%11100%
File 3: get_Metadata()100%11100%
File 3: get_ActivityNode()100%11100%
File 3: get_NodeId()100%11100%
File 3: get_Children()100%11100%
File 3: get_Bookmarks()100%11100%
File 3: get_NewBookmarks()100%11100%
File 3: get_ExecutionCount()100%210%
File 3: get_WorkflowInput()100%11100%
File 3: get_ActivityInput()100%11100%
File 3: get_JournalData()100%11100%
File 3: get_ActivityState()100%11100%
File 3: get_IsDirty()100%11100%
File 3: ScheduleActivityAsync(...)100%22100%
File 3: ScheduleActivityAsync()100%11100%
File 3: ScheduleActivityAsync()100%11100%
File 3: ScheduleActivityAsync()100%210%
File 3: ScheduleActivitiesAsync()100%210%
File 3: ScheduleActivities(...)50%22100%
File 3: ScheduleActivities()100%22100%
File 3: CreateBookmarks(...)100%22100%
File 3: AddBookmarks(...)100%210%
File 3: AddBookmark(...)100%11100%
File 3: CreateBookmark(...)100%210%
File 3: CreateBookmark(...)100%210%
File 3: CreateBookmark(...)100%210%
File 3: CreateBookmark(...)100%11100%
File 3: CreateBookmark(...)100%2424100%
File 3: ClearBookmarks()100%11100%
File 3: GetProperty(...)100%22100%
File 3: GetProperty(...)100%22100%
File 3: SetProperty(...)100%11100%
File 3: UpdateProperty(...)100%11100%
File 3: RemoveProperty(...)100%210%
File 3: GetMetadata(...)0%620%
File 3: GetMetadata(...)100%22100%
File 3: SetMetadata(...)100%11100%
File 3: UpdateMetadata(...)100%210%
File 3: RemoveMetadata(...)100%210%
File 3: GetRequiredService()100%11100%
File 3: GetRequiredService(...)100%11100%
File 3: GetOrCreateService()100%210%
File 3: GetOrCreateService(...)100%210%
File 3: GetService()100%11100%
File 3: GetServices()100%11100%
File 3: GetService(...)100%210%
File 3: Get(...)100%22100%
File 3: Get(...)0%620%
File 3: Get(...)100%22100%
File 3: Get(...)50%22100%
File 3: Get(...)100%22100%
File 3: TryGet(...)25%7444.44%
File 3: Set(...)100%11100%
File 3: Set(...)100%11100%
File 3: Set(...)100%11100%
File 3: ClearCompletionCallbacks()100%11100%
File 3: Taint()100%22100%
File 3: ClearTaint()100%22100%
File 3: IncrementExecutionCount()100%11100%
File 3: GetMemoryBlock(...)50%22100%
File 3: System.IDisposable.Dispose()100%210%
File 4: AddExecutionLogEntry(...)100%44100%

File(s)

/home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Workflows.Core/Contexts/ActivityExecutionContext.Cancel.cs

#LineLine coverage
 1using Elsa.Extensions;
 2using Elsa.Mediator.Contracts;
 3using Elsa.Workflows.Notifications;
 4using Elsa.Workflows.Signals;
 5
 6namespace Elsa.Workflows;
 7
 8public partial class ActivityExecutionContext
 9{
 10    private readonly INotificationSender _publisher;
 11
 12    private bool CanCancelActivity()
 13    {
 268614        return Status is not ActivityStatus.Canceled and not ActivityStatus.Completed;
 15    }
 16
 17    private async Task CancelActivityAsync()
 18    {
 619        if(!CanCancelActivity())
 020            return;
 21
 622        TransitionTo(ActivityStatus.Canceled);
 623        ClearBookmarks();
 624        ClearCompletionCallbacks();
 1125        WorkflowExecutionContext.Bookmarks.RemoveWhere(x => x.ActivityNodeId == NodeId);
 626        AddExecutionLogEntry("Canceled");
 627        await this.SendSignalAsync(new CancelSignal());
 628        await CancelChildActivitiesAsync();
 29
 30        // ReSharper disable once MethodSupportsCancellation
 631        await _publisher.SendAsync(new ActivityCancelled(this));
 632    }
 33
 34    private async Task CancelChildActivitiesAsync()
 35    {
 3236        var childContexts = WorkflowExecutionContext.ActivityExecutionContexts.Where(x => x.ParentActivityExecutionConte
 37
 1238        foreach (var childContext in childContexts)
 039            await childContext.CancelActivityAsync();
 640    }
 41}

/home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Workflows.Core/Contexts/ActivityExecutionContext.Complete.cs

#LineLine coverage
 1using Elsa.Extensions;
 2using Elsa.Mediator.Contracts;
 3using Elsa.Workflows.Activities.Flowchart.Models;
 4using Elsa.Workflows.Signals;
 5
 6namespace Elsa.Workflows;
 7
 8public partial class ActivityExecutionContext
 9{
 10    /// <summary>
 11    /// Complete the current activity. This should only be called by activities that explicitly suppress automatic-compl
 12    /// </summary>
 13    public async ValueTask CompleteActivityAsync(object? result = null)
 14    {
 339615        var outcomes = result as Outcomes;
 16
 17        // If the activity is executing in the background, simply capture the result and return.
 339618        if (this.GetIsBackgroundExecution())
 19        {
 020            if (outcomes != null)
 021                this.SetBackgroundOutcomes(outcomes.Names);
 22            else
 023                this.SetBackgroundCompletion();
 024            return;
 25        }
 26
 27        // If the activity is not running, do nothing.
 339628        if (Status != ActivityStatus.Running)
 729            return;
 30
 31        // Cancel any non-completed child activities.
 606932        var childContexts = Children.Where(x => x.CanCancelActivity()).ToList();
 33
 679034        foreach (var childContext in childContexts)
 635            await childContext.CancelActivityAsync();
 36
 37        // Mark the activity as complete.
 338938        TransitionTo(ActivityStatus.Completed);
 39
 40        // Record the outcomes, if any.
 338941        if (outcomes != null)
 10542            JournalData["Outcomes"] = outcomes.Names;
 43
 44        // Add an execution log entry.
 338945        AddExecutionLogEntry("Completed");
 46
 47        // Send a signal.
 338948        await this.SendSignalAsync(new ActivityCompleted(result));
 49
 50        // Clear bookmarks.
 338951        ClearBookmarks();
 342252        WorkflowExecutionContext.Bookmarks.RemoveWhere(x => x.ActivityInstanceId == Id);
 53
 54        // Remove completion callbacks.
 338955        ClearCompletionCallbacks();
 56
 57        // Remove all associated variables, unless this is the root context - in which case we want to keep the variable
 338958        if (ParentActivityExecutionContext != null)
 59        {
 274060            var variablePersistenceManager = GetRequiredService<IVariablePersistenceManager>();
 274061            await variablePersistenceManager.DeleteVariablesAsync(this);
 62        }
 63
 64        // Update the completed at timestamp.
 338965        CompletedAt = WorkflowExecutionContext.SystemClock.UtcNow;
 339666    }
 67
 68    /// <summary>
 69    /// Complete the current activity with the specified outcomes.
 70    /// </summary>
 71    public ValueTask CompleteActivityWithOutcomesAsync(params string[] outcomes)
 72    {
 10073        return CompleteActivityAsync(new Outcomes(outcomes));
 74    }
 75
 76    /// <summary>
 77    /// Complete the current composite activity with the specified outcome.
 78    /// </summary>
 79    public async ValueTask CompleteCompositeAsync(params string[] outcomes)
 80    {
 081        await this.SendSignalAsync(new CompleteCompositeSignal(new Outcomes(outcomes)));
 082    }
 83}

/home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Workflows.Core/Contexts/ActivityExecutionContext.cs

#LineLine coverage
 1using System.Runtime.CompilerServices;
 2using Elsa.Common;
 3using Elsa.Expressions.Helpers;
 4using Elsa.Expressions.Models;
 5using Elsa.Extensions;
 6using Elsa.Mediator.Contracts;
 7using Elsa.Workflows.Memory;
 8using Elsa.Workflows.Models;
 9using Elsa.Workflows.Options;
 10using JetBrains.Annotations;
 11
 12namespace Elsa.Workflows;
 13
 14/// <summary>
 15/// Represents the context of an activity execution.
 16/// </summary>
 17[PublicAPI]
 18public partial class ActivityExecutionContext : IExecutionContext, IDisposable
 19{
 20    private readonly ISystemClock _systemClock;
 21    private ActivityStatus _status;
 22    private Exception? _exception;
 23    private long _executionCount;
 24    private ActivityExecutionContext? _parentActivityExecutionContext;
 25
 26    // Bookmarks created during the lifetime of this activity.
 392527    private List<Bookmark> _newBookmarks = [];
 28
 29    /// <summary>
 30    /// Initializes a new instance of the <see cref="ActivityExecutionContext"/> class.
 31    /// </summary>
 392532    public ActivityExecutionContext(
 392533        string id,
 392534        WorkflowExecutionContext workflowExecutionContext,
 392535        ActivityExecutionContext? parentActivityExecutionContext,
 392536        IActivity activity,
 392537        ActivityDescriptor activityDescriptor,
 392538        DateTimeOffset startedAt,
 392539        object? tag,
 392540        ISystemClock systemClock,
 392541        CancellationToken cancellationToken)
 42    {
 392543        _systemClock = systemClock;
 392544        Properties = new ChangeTrackingDictionary<string, object>(Taint);
 392545        Metadata = new ChangeTrackingDictionary<string, object>(Taint);
 392546        ActivityState = new ChangeTrackingDictionary<string, object>(Taint);
 392547        ActivityInput = new ChangeTrackingDictionary<string, object>(Taint);
 392548        WorkflowExecutionContext = workflowExecutionContext;
 392549        ParentActivityExecutionContext = parentActivityExecutionContext;
 392550        var expressionExecutionContextProps = ExpressionExecutionContextExtensions.CreateActivityExecutionContextPropert
 392551        expressionExecutionContextProps[ExpressionExecutionContextExtensions.ActivityKey] = activity;
 392552        ExpressionExecutionContext = new(workflowExecutionContext.ServiceProvider, new(), parentActivityExecutionContext
 392553        Activity = activity;
 392554        ActivityDescriptor = activityDescriptor;
 392555        StartedAt = startedAt;
 392556        Status = ActivityStatus.Pending;
 392557        Tag = tag;
 392558        CancellationToken = cancellationToken;
 392559        Id = id;
 392560        _publisher = GetRequiredService<INotificationSender>();
 392561    }
 62
 63    /// <summary>
 64    /// The ID of the current activity execution context.
 65    /// </summary>
 4628266    public string Id { get; set; }
 67
 68    /// <summary>
 69    /// The time at which the activity execution context was created.
 70    /// </summary>
 814071    public DateTimeOffset StartedAt { get; set; }
 72
 73    /// <summary>
 74    /// An optional tag to associate with the activity execution.
 75    /// </summary>
 749176    public object? Tag { get; set; }
 77
 78    /// <summary>
 79    /// The time at which the activity execution context was completed.
 80    /// </summary>
 759981    public DateTimeOffset? CompletedAt { get; set; }
 82
 83    /// <summary>
 84    /// Returns true if the activity execution context has completed.
 85    /// </summary>
 1338186    public bool IsCompleted => Status is ActivityStatus.Completed or ActivityStatus.Canceled;
 87
 88    /// <summary>
 89    /// Gets or sets a value indicating whether the activity is actively executing.
 90    /// </summary>
 91    /// <remarks>
 92    /// This flag is set to <c>true</c> immediately before the activity begins execution
 93    /// and is set to <c>false</c> once the execution is completed.
 94    /// It can be used to determine if an activity was in-progress in case of unexpected
 95    /// application termination, allowing the system to retry execution upon restarting.
 96    /// </remarks>
 739597    public bool IsExecuting { get; set; }
 98
 99    /// <summary>
 100    /// The number of faults encountered during the execution of the activity and its descendants.
 101    /// </summary>
 4297102    public int AggregateFaultCount { get; set; }
 103
 104    /// <summary>
 105    /// The workflow execution context.
 106    /// </summary>
 168408107    public WorkflowExecutionContext WorkflowExecutionContext { get; }
 108
 109    /// <summary>
 110    /// The parent activity execution context, if any.
 111    /// This represents the structural container activity (e.g., Flowchart contains all its children).
 112    /// </summary>
 113    public ActivityExecutionContext? ParentActivityExecutionContext
 114    {
 61888115        get => _parentActivityExecutionContext;
 116        internal set
 117        {
 4022118            _parentActivityExecutionContext = value;
 4022119            _parentActivityExecutionContext?.Children.Add(this);
 2921120        }
 121    }
 122
 123    /// <summary>
 124    /// The ID of the activity execution context that scheduled this activity execution.
 125    /// This represents the temporal/execution predecessor that directly triggered execution of this activity,
 126    /// distinct from <see cref="ParentActivityExecutionContext"/> which represents the structural container.
 127    /// For example, in a Flowchart, Activity B might complete and schedule Activity C, making B the scheduling activity
 128    /// </summary>
 7367129    public string? SchedulingActivityExecutionId { get; set; }
 130
 131    /// <summary>
 132    /// The ID of the activity that scheduled this activity execution (denormalized for convenience).
 133    /// This is the Activity.Id from the activity execution context identified by <see cref="SchedulingActivityExecution
 134    /// </summary>
 6215135    public string? SchedulingActivityId { get; set; }
 136
 137    /// <summary>
 138    /// The workflow instance ID of the workflow that scheduled this activity execution.
 139    /// This is set when crossing workflow boundaries (e.g., via ExecuteWorkflow or DispatchWorkflow).
 140    /// For activities within the same workflow instance, this will be null.
 141    /// </summary>
 7336142    public string? SchedulingWorkflowInstanceId { get; set; }
 143
 144    /// <summary>
 145    /// The depth of this activity in the call stack (0 for root activities).
 146    /// </summary>
 9834147    public int CallStackDepth { get; set; }
 148
 149    /// <summary>
 150    /// The expression execution context.
 151    /// </summary>
 45258152    public ExpressionExecutionContext ExpressionExecutionContext { get; }
 153
 154    /// <inheritdoc />
 155    public IEnumerable<Variable> Variables
 156    {
 157        get
 158        {
 6348159            var containerVariables = (Activity as IVariableContainer)?.Variables ?? Enumerable.Empty<Variable>();
 6348160            var dynamicVariables = DynamicVariables;
 6348161            var mergedVariables = new Dictionary<string, Variable>();
 162
 12964163            foreach (var containerVariable in containerVariables)
 164            {
 134165                var name = !string.IsNullOrEmpty(containerVariable.Name) ? containerVariable.Name : containerVariable.Id
 134166                mergedVariables[name] = containerVariable;
 167            }
 168
 13066169            foreach (var dynamicVariable in dynamicVariables)
 170            {
 185171                var name = !string.IsNullOrEmpty(dynamicVariable.Name) ? dynamicVariable.Name : dynamicVariable.Id;
 185172                mergedVariables[name] = dynamicVariable;
 173            }
 6348174            return mergedVariables.Values;
 175        }
 176    }
 177
 178    /// <summary>
 179    /// A list of variables that are dynamically added to the activity execution context.
 180    /// </summary>
 11242181    public ICollection<Variable> DynamicVariables { get; set; } = new List<Variable>();
 182
 183    /// <summary>
 184    /// The currently executing activity.
 185    /// </summary>
 202906186    public IActivity Activity { get; set; }
 187
 188    /// <summary>
 189    /// The activity descriptor.
 190    /// </summary>
 25901191    public ActivityDescriptor ActivityDescriptor { get; }
 192
 193    /// <summary>
 194    /// A cancellation token to use when invoking asynchronous operations.
 195    /// </summary>
 34377196    public CancellationToken CancellationToken { get; }
 197
 198    /// <summary>
 199    /// The current status of the activity.
 200    /// </summary>
 201    public ActivityStatus Status
 202    {
 50015203        get => _status;
 204        private set
 205        {
 11203206            if (value == _status)
 3961207                return;
 208
 7242209            _status = value;
 7242210            Taint();
 7242211        }
 212    }
 213
 214    public IDisposable EnterExecution()
 215    {
 3300216        return new WorkflowExecutionState(this);
 217    }
 218
 219    /// <summary>
 220    /// Sets the current status of the activity.
 221    /// </summary>
 222    public void TransitionTo(ActivityStatus status)
 223    {
 7278224        Status = status;
 7278225    }
 226
 227    /// <summary>
 228    /// Gets or sets the exception that occurred during the activity execution, if any.
 229    /// </summary>
 230    public Exception? Exception
 231    {
 3418232        get => _exception;
 233        set
 234        {
 15235            _exception = value;
 15236            Taint();
 15237        }
 238    }
 239
 240    /// <inheritdoc />
 12939241    public IDictionary<string, object> Properties { get; private set; }
 242
 243    /// <summary>
 244    /// A transient dictionary of values that can be associated with this activity execution context.
 245    /// These properties only exist while the activity executes and are not persisted.
 246    /// </summary>
 44444247    public IDictionary<object, object> TransientProperties { get; set; } = new Dictionary<object, object>();
 248
 249    /// <summary>
 250    /// A dictionary of metadata about this execution. In contrast to <see cref="Properties"/>, this metadata is never p
 251    /// </summary>
 8195252    public IDictionary<string, object> Metadata { get; private set; }
 253
 254    /// <summary>
 255    /// Returns the <see cref="ActivityNode"/> metadata about the current activity.
 256    /// </summary>
 31888257    public ActivityNode ActivityNode => WorkflowExecutionContext.FindNodeByActivity(Activity)!;
 258
 259    /// <summary>
 260    /// Returns the global node ID for the current activity within the graph.
 261    /// </summary>
 262    /// <remarks>As of tool version 3.0, all activity IDs are already unique, so there's no need to construct a hierarch
 11081263    public string NodeId => ActivityNode.NodeId;
 264
 14695265    public ISet<ActivityExecutionContext> Children { get; } = new HashSet<ActivityExecutionContext>();
 266
 267    /// <summary>
 268    /// A list of bookmarks associated with the current activity.
 269    /// </summary>
 3592270    public IEnumerable<Bookmark> Bookmarks => WorkflowExecutionContext.Bookmarks.Where(x => x.ActivityInstanceId == Id);
 271
 272    /// <summary>
 273    /// A collection of bookmarks created during the execution of the activity.
 274    /// </summary>
 689275    public IEnumerable<Bookmark> NewBookmarks => _newBookmarks.AsReadOnly();
 276
 277    /// <summary>
 278    /// The number of times this <see cref="ActivityExecutionContext"/> has executed.
 279    /// </summary>
 0280    public long ExecutionCount => _executionCount;
 281
 282    /// <summary>
 283    /// A dictionary of received inputs for the current workflow.
 284    /// </summary>
 292285    public IDictionary<string, object> WorkflowInput => WorkflowExecutionContext.Input;
 286
 287    /// <summary>
 288    /// A dictionary of inputs for the current activity.
 289    /// </summary>
 7980290    public IDictionary<string, object> ActivityInput { get; private set; }
 291
 292    /// <summary>
 293    /// Journal data will be added to the workflow execution log for the "Executed" event.
 294    /// </summary>
 295    // ReSharper disable once CollectionNeverQueried.Global
 7492296    public IDictionary<string, object> JournalData { get; } = new Dictionary<string, object>();
 297
 298    /// <summary>
 299    /// Stores the evaluated inputs, serialized, for the current activity for historical purposes.
 300    /// </summary>
 10418301    public IDictionary<string, object> ActivityState { get; }
 302
 303    /// <summary>
 304    /// Indicates whether the state of the current activity execution context has been modified.
 305    /// </summary>
 31263306    public bool IsDirty { get; private set; }
 307
 308    /// <summary>
 309    /// Schedules the specified activity to be executed.
 310    /// </summary>
 311    /// <param name="activity">The activity to schedule.</param>
 312    /// <param name="completionCallback">An optional callback to invoke when the activity completes.</param>
 313    /// <param name="tag">An optional tag to associate with the activity execution.</param>
 314    /// <param name="variables">An optional list of variables to declare with the activity execution.</param>
 315    public ValueTask ScheduleActivityAsync(IActivity? activity, ActivityCompletionCallback? completionCallback, object? 
 316    {
 2128317        var options = new ScheduleWorkOptions
 2128318        {
 2128319            CompletionCallback = completionCallback,
 2128320            Tag = tag,
 2128321            Variables = variables?.ToList()
 2128322        };
 2128323        return ScheduleActivityAsync(activity, options);
 324    }
 325
 326    /// <summary>
 327    /// Schedules the specified activity to be executed.
 328    /// </summary>
 329    /// <param name="activity">The activity to schedule.</param>
 330    /// <param name="options">The options used to schedule the activity.</param>
 331    public async ValueTask ScheduleActivityAsync(IActivity? activity, ScheduleWorkOptions? options = null)
 332    {
 2997333        await ScheduleActivityAsync(activity, this, options);
 2997334    }
 335
 336    /// <summary>
 337    /// Schedules the specified activity to be executed.
 338    /// </summary>
 339    /// <param name="activity">The activity to schedule.</param>
 340    /// <param name="owner">The activity execution context that owns the scheduled activity.</param>
 341    /// <param name="options">The options used to schedule the activity.</param>
 342    public async ValueTask ScheduleActivityAsync(IActivity? activity, ActivityExecutionContext? owner, ScheduleWorkOptio
 343    {
 2997344        var schedulerStrategy = GetRequiredService<IActivityExecutionContextSchedulerStrategy>();
 2997345        await schedulerStrategy.ScheduleActivityAsync(this, activity, owner, options);
 2997346    }
 347
 348    /// <summary>
 349    /// Schedules the specified activity to be executed.
 350    /// </summary>
 351    /// <param name="activityNode">The activity node to schedule.</param>
 352    /// <param name="owner">The activity execution context that owns the scheduled activity.</param>
 353    /// <param name="options">The options used to schedule the activity.</param>
 354    public async Task ScheduleActivityAsync(ActivityNode? activityNode, ActivityExecutionContext? owner = null, Schedule
 355    {
 0356        var schedulerStrategy = GetRequiredService<IActivityExecutionContextSchedulerStrategy>();
 0357        await schedulerStrategy.ScheduleActivityAsync(this, activityNode, owner, options);
 0358    }
 359
 360    /// <summary>
 361    /// Schedules the specified activities to be executed.
 362    /// </summary>
 363    /// <param name="activities">The activities to schedule.</param>
 0364    public async ValueTask ScheduleActivitiesAsync(params IActivity?[] activities) => await ScheduleActivities(activitie
 365
 366    /// <summary>
 367    /// Schedules the specified activities to be executed.
 368    /// </summary>
 369    /// <param name="activities">The activities to schedule.</param>
 370    /// <param name="completionCallback">The callback to invoke when the activities complete.</param>
 371    /// <param name="tag">An optional tag to associate with the activity execution.</param>
 372    /// <param name="variables">An optional list of variables to declare with the activity execution.</param>
 373    public ValueTask ScheduleActivities(IEnumerable<IActivity?> activities, ActivityCompletionCallback? completionCallba
 374    {
 8375        var options = new ScheduleWorkOptions
 8376        {
 8377            CompletionCallback = completionCallback,
 8378            Tag = tag,
 8379            Variables = variables?.ToList()
 8380        };
 8381        return ScheduleActivities(activities, options);
 382    }
 383
 384    /// <summary>
 385    /// Schedules the specified activities to be executed.
 386    /// </summary>
 387    /// <param name="activities">The activities to schedule.</param>
 388    /// <param name="options">The options used to schedule the activities.</param>
 389    public async ValueTask ScheduleActivities(IEnumerable<IActivity?> activities, ScheduleWorkOptions? options = null)
 390    {
 48391        foreach (var activity in activities)
 16392            await ScheduleActivityAsync(activity, options);
 8393    }
 394
 395    /// <summary>
 396    /// Creates a bookmark for each payload.
 397    /// </summary>
 398    /// <param name="payloads">The payloads to create bookmarks for.</param>
 399    /// <param name="callback">An optional callback that is invoked when the bookmark is resumed.</param>
 400    /// <param name="includeActivityInstanceId">Whether or not the activity instance ID should be included in the bookma
 401    /// <param name="bookmarkName">An optional name to use for the bookmark. Defaults to the activity type.</param>
 402    public void CreateBookmarks(IEnumerable<object> payloads, ExecuteActivityDelegate? callback = null, bool includeActi
 403    {
 28404        foreach (var payload in payloads)
 7405            CreateBookmark(new()
 7406            {
 7407                Stimulus = payload,
 7408                Callback = callback,
 7409                BookmarkName = bookmarkName,
 7410                IncludeActivityInstanceId = includeActivityInstanceId
 7411            });
 7412    }
 413
 414    /// <summary>
 415    /// Adds each bookmark to the list of bookmarks.
 416    /// </summary>
 417    /// <param name="bookmarks">The bookmarks to add.</param>
 418    public void AddBookmarks(IEnumerable<Bookmark> bookmarks)
 419    {
 0420        WorkflowExecutionContext.Bookmarks.AddRange(bookmarks);
 0421        Taint();
 0422    }
 423
 424    /// <summary>
 425    /// Adds a bookmark to the list of bookmarks.
 426    /// </summary>
 427    /// <param name="bookmark">The bookmark to add.</param>
 428    public void AddBookmark(Bookmark bookmark)
 429    {
 70430        _newBookmarks.Add(bookmark);
 70431        WorkflowExecutionContext.Bookmarks.Add(bookmark);
 70432        Taint();
 70433    }
 434
 435    /// <summary>
 436    /// Creates a bookmark so that this activity can be resumed at a later time.
 437    /// </summary>
 438    /// <param name="callback">An optional callback that is invoked when the bookmark is resumed.</param>
 439    /// <param name="metadata">Custom properties to associate with the bookmark.</param>
 440    /// <returns>The created bookmark.</returns>
 441    public Bookmark CreateBookmark(ExecuteActivityDelegate callback, IDictionary<string, string>? metadata = null)
 442    {
 0443        return CreateBookmark(new()
 0444        {
 0445            Callback = callback,
 0446            Metadata = metadata
 0447        });
 448    }
 449
 450    /// <summary>
 451    /// Creates a bookmark so that this activity can be resumed at a later time.
 452    /// </summary>
 453    /// <param name="stimulus">The payload to associate with the bookmark.</param>
 454    /// <param name="callback">An optional callback that is invoked when the bookmark is resumed.</param>
 455    /// <param name="includeActivityInstanceId">Whether or not the activity instance ID should be included in the bookma
 456    /// <param name="customProperties">Custom properties to associate with the bookmark.</param>
 457    /// <returns>The created bookmark.</returns>
 458    public Bookmark CreateBookmark(object stimulus, ExecuteActivityDelegate? callback, bool includeActivityInstanceId = 
 459    {
 0460        return CreateBookmark(new()
 0461        {
 0462            Stimulus = stimulus,
 0463            Callback = callback,
 0464            IncludeActivityInstanceId = includeActivityInstanceId,
 0465            Metadata = customProperties
 0466        });
 467    }
 468
 469    /// <summary>
 470    /// Creates a bookmark for the current activity execution context.
 471    /// </summary>
 472    /// <param name="stimulus">The payload to associate with the bookmark.</param>
 473    /// <param name="includeActivityInstanceId">Specifies whether to include the activity instance ID in the bookmark in
 474    /// <param name="customProperties">Additional custom properties to associate with the bookmark. Defaults to null.</p
 475    /// <returns>The created bookmark.</returns>
 476    public Bookmark CreateBookmark(object stimulus, bool includeActivityInstanceId, IDictionary<string, string>? customP
 477    {
 0478        return CreateBookmark(new()
 0479        {
 0480            Stimulus = stimulus,
 0481            IncludeActivityInstanceId = includeActivityInstanceId,
 0482            Metadata = customProperties
 0483        });
 484    }
 485
 486    /// <summary>
 487    /// Creates a bookmark so that this activity can be resumed at a later time.
 488    /// </summary>
 489    /// <param name="stimulus">The payload to associate with the bookmark.</param>
 490    /// <param name="metadata">Custom properties to associate with the bookmark.</param>
 491    /// <returns>The created bookmark.</returns>
 492    public Bookmark CreateBookmark(object stimulus, IDictionary<string, string>? metadata = null)
 493    {
 9494        return CreateBookmark(new()
 9495        {
 9496            Stimulus = stimulus,
 9497            Metadata = metadata
 9498        });
 499    }
 500
 501    /// <summary>
 502    /// Creates a bookmark so that this activity can be resumed at a later time.
 503    /// Creating a bookmark will automatically suspend the workflow after all pending activities have executed.
 504    /// </summary>
 505    public Bookmark CreateBookmark(CreateBookmarkArgs? options = null)
 506    {
 70507        var payload = options?.Stimulus;
 70508        var callback = options?.Callback;
 70509        var bookmarkName = options?.BookmarkName ?? Activity.Type;
 70510        var bookmarkHasher = GetRequiredService<IStimulusHasher>();
 70511        var identityGenerator = GetRequiredService<IIdentityGenerator>();
 70512        var includeActivityInstanceId = options?.IncludeActivityInstanceId ?? true;
 70513        var hash = bookmarkHasher.Hash(bookmarkName, payload, includeActivityInstanceId ? Id : null);
 70514        var bookmarkId = options?.BookmarkId ?? identityGenerator.GenerateId();
 515
 70516        var bookmark = new Bookmark(
 70517            bookmarkId,
 70518            bookmarkName,
 70519            hash,
 70520            payload,
 70521            Activity.Id,
 70522            ActivityNode.NodeId,
 70523            Id,
 70524            _systemClock.UtcNow,
 70525            options?.AutoBurn ?? true,
 70526            callback?.Method.Name,
 70527            options?.AutoComplete ?? true,
 70528            options?.Metadata);
 529
 70530        AddBookmark(bookmark);
 70531        return bookmark;
 532    }
 533
 534    /// <summary>
 535    /// Clear all bookmarks.
 536    /// </summary>
 537    public void ClearBookmarks()
 538    {
 3398539        _newBookmarks.Clear();
 3470540        WorkflowExecutionContext.Bookmarks.RemoveWhere(x => x.ActivityInstanceId == Id);
 3398541        Taint();
 3398542    }
 543
 544    /// <summary>
 545    /// Returns a property value associated with the current activity context.
 546    /// </summary>
 1468547    public T? GetProperty<T>(string key) => Properties.TryGetValue<T?>(key, out var value) ? value : default;
 548
 549    /// <summary>
 550    /// Returns a property value associated with the current activity context.
 551    /// </summary>
 552    public T GetProperty<T>(string key, Func<T> defaultValue)
 553    {
 136554        if (Properties.TryGetValue<T?>(key, out var value))
 102555            return value!;
 556
 34557        value = defaultValue();
 34558        Properties[key] = value!;
 559
 34560        return value!;
 561    }
 562
 563    /// <summary>
 564    /// Stores a property associated with the current activity context.
 565    /// </summary>
 141566    public void SetProperty<T>(string key, T? value) => Properties[key] = value!;
 567
 568    /// <summary>
 569    /// Updates a property associated with the current activity context.
 570    /// </summary>
 571    public T UpdateProperty<T>(string key, Func<T?, T> updater) where T : notnull
 572    {
 372573        var value = GetProperty<T?>(key);
 372574        value = updater(value);
 372575        Properties[key] = value;
 372576        return value;
 577    }
 578
 579    /// <summary>
 580    /// Removes a property associated with the current activity context.
 581    /// </summary>
 582    /// <param name="key">The property key.</param>
 0583    public void RemoveProperty(string key) => Properties.Remove(key);
 584
 585    /// <summary>
 586    /// Returns a metadata value associated with the current activity context.
 587    /// </summary>
 0588    public T? GetMetadata<T>(string key) => Metadata.TryGetValue<T?>(key, out var value) ? value : default;
 589
 590    /// <summary>
 591    /// Returns a metadata value associated with the current activity context.
 592    /// </summary>
 593    public T GetMetadata<T>(string key, Func<T> defaultValue)
 594    {
 29595        if (Metadata.TryGetValue<T?>(key, out var value))
 13596            return value!;
 597
 16598        value = defaultValue();
 16599        Metadata[key] = value!;
 600
 16601        return value!;
 602    }
 603
 604    /// <summary>
 605    /// Stores a metadata value associated with the current activity context.
 606    /// </summary>
 4607    public void SetMetadata<T>(string key, T? value) => Metadata[key] = value!;
 608
 609    /// <summary>
 610    /// Updates a metadata value associated with the current activity context.
 611    /// </summary>
 612    public T UpdateMetadata<T>(string key, Func<T?, T> updater) where T : notnull
 613    {
 0614        var value = GetMetadata<T?>(key);
 0615        value = updater(value);
 0616        Metadata[key] = value;
 0617        return value;
 618    }
 619
 620    /// <summary>
 621    /// Removes a metadata value associated with the current activity context.
 622    /// </summary>
 623    /// <param name="key">The metadata key.</param>
 0624    public void RemoveMetadata(string key) => Metadata.Remove(key);
 625
 626    /// <summary>
 627    /// Resolves a required service using the service provider.
 628    /// </summary>
 629    /// <typeparam name="T">The service type.</typeparam>
 630    /// <returns>The resolved service.</returns>
 33437631    public T GetRequiredService<T>() where T : notnull => WorkflowExecutionContext.GetRequiredService<T>();
 632
 633    /// <summary>
 634    /// Resolves a required service using the service provider.
 635    /// </summary>
 636    /// <param name="serviceType">The service type.</param>
 637    /// <returns>The resolved service.</returns>
 3012638    public object GetRequiredService(Type serviceType) => WorkflowExecutionContext.GetRequiredService(serviceType);
 639
 640    /// <summary>
 641    /// Resolves a service using the service provider. If not found, a new instance is created.
 642    /// </summary>
 643    /// <typeparam name="T">The service type.</typeparam>
 644    /// <returns>The resolved service.</returns>
 0645    public T GetOrCreateService<T>() where T : notnull => WorkflowExecutionContext.GetOrCreateService<T>();
 646
 647    /// <summary>
 648    /// Resolves a service using the service provider. If not found, a new instance is created.
 649    /// </summary>
 650    /// <param name="serviceType">The service type.</param>
 651    /// <returns>The resolved service.</returns>
 0652    public object GetOrCreateService(Type serviceType) => WorkflowExecutionContext.GetOrCreateService(serviceType);
 653
 654    /// <summary>
 655    /// Resolves a service using the service provider.
 656    /// </summary>
 657    /// <typeparam name="T">The service type.</typeparam>
 658    /// <returns>The resolved service.</returns>
 590659    public T? GetService<T>() where T : notnull => WorkflowExecutionContext.GetService<T>();
 660
 661    /// <summary>
 662    /// Resolves all services of the specified type using the service provider.
 663    /// </summary>
 664    /// <typeparam name="T">The service type.</typeparam>
 665    /// <returns>The resolved services.</returns>
 263666    public IEnumerable<T> GetServices<T>() where T : notnull => WorkflowExecutionContext.GetServices<T>();
 667
 668    /// <summary>
 669    /// Resolves a service using the service provider.
 670    /// </summary>
 671    /// <param name="serviceType">The service type.</param>
 672    /// <returns>The resolved service.</returns>
 0673    public object? GetService(Type serviceType) => WorkflowExecutionContext.GetService(serviceType);
 674
 675    /// <summary>
 676    /// Gets the value of the specified input.
 677    /// </summary>
 678    /// <param name="input">The input.</param>
 679    /// <typeparam name="T">The type of the input.</typeparam>
 680    /// <returns>The input value.</returns>
 3102681    public T? Get<T>(Input<T>? input) => input == null ? default : Get<T>(input.MemoryBlockReference());
 682
 683    /// <summary>
 684    /// Gets the value of the specified output.
 685    /// </summary>
 686    /// <param name="output">The output.</param>
 687    /// <typeparam name="T">The type of the output.</typeparam>
 688    /// <returns>The output value.</returns>
 0689    public T? Get<T>(Output<T>? output) => output == null ? default : Get<T>(output.MemoryBlockReference());
 690
 691    /// <summary>
 692    /// Gets the value of the specified output.
 693    /// </summary>
 694    /// <param name="output">The output.</param>
 695    /// <returns>The output value.</returns>
 4696    public object? Get(Output? output) => output == null ? null : Get(output.MemoryBlockReference());
 697
 698    /// <summary>
 699    /// Gets the value of the specified memory block.
 700    /// </summary>
 701    /// <param name="blockReference">The memory block reference.</param>
 702    /// <returns>The memory block value.</returns>
 703    /// <exception cref="InvalidOperationException">The memory block does not exist.</exception>
 704    public object? Get(MemoryBlockReference blockReference)
 705    {
 2234706        return !TryGet(blockReference, out var value)
 2234707            ? throw new InvalidOperationException($"The memory block '{blockReference}' does not exist.")
 2234708            : value;
 709    }
 710
 711    /// <summary>
 712    /// Gets the value of the specified memory block.
 713    /// </summary>
 714    /// <param name="blockReference">The memory block reference.</param>
 715    /// <typeparam name="T">The type of the memory block.</typeparam>
 716    /// <returns>The memory block value.</returns>
 717    public T? Get<T>(MemoryBlockReference blockReference)
 718    {
 2108719        var value = Get(blockReference);
 2108720        return value != null ? value.ConvertTo<T>() : default;
 721    }
 722
 723    /// <summary>
 724    /// Tries to get the value of the specified memory block.
 725    /// </summary>
 726    /// <param name="blockReference">The memory block reference.</param>
 727    /// <param name="value">The memory block value.</param>
 728    /// <returns>True if the memory block exists, false otherwise.</returns>
 729    public bool TryGet(MemoryBlockReference blockReference, out object? value)
 730    {
 731        // First, try to get the value from the memory register
 2412732        var memoryBlock = GetMemoryBlock(blockReference);
 733
 2412734        if (memoryBlock != null)
 735        {
 2412736            value = memoryBlock.Value;
 2412737            return true;
 738        }
 739
 740        // Handle Literal references as a fallback - they can hold their value directly
 0741        if (blockReference is Literal literal)
 742        {
 0743            value = literal.Value;
 0744            return true;
 745        }
 746
 0747        value = null;
 0748        return false;
 749    }
 750
 751    /// <summary>
 752    /// Sets a value at the specified memory block.
 753    /// </summary>
 754    /// <param name="blockReference">The memory block reference.</param>
 755    /// <param name="value">The value to set.</param>
 756    /// <param name="configure">An optional callback that can be used to configure the memory block.</param>
 6757    public void Set(MemoryBlockReference blockReference, object? value, Action<MemoryBlock>? configure = null) => Expres
 758
 759    /// <summary>
 760    /// Sets a value at the specified output.
 761    /// </summary>
 762    /// <param name="output">The output.</param>
 763    /// <param name="value">The value to set.</param>
 764    /// <param name="outputName">The name of the output.</param>
 765    /// <typeparam name="T">The type of the output.</typeparam>
 1676766    public void Set<T>(Output<T>? output, T? value, [CallerArgumentExpression("output")] string? outputName = null) => S
 767
 768    /// <summary>
 769    /// Sets a value at the specified output.
 770    /// </summary>
 771    /// <param name="output">The output.</param>
 772    /// <param name="value">The value to set.</param>
 773    /// <param name="outputName">The name of the output.</param>
 774    public void Set(Output? output, object? value, [CallerArgumentExpression("output")] string? outputName = null)
 775    {
 776        // Store the value in the expression execution memory block.
 1704777        ExpressionExecutionContext.Set(output, value);
 778
 779        // Also store the value in the workflow execution transient activity output register.
 1704780        WorkflowExecutionContext.RecordActivityOutput(this, outputName, value);
 1704781    }
 782
 783    /// <summary>
 784    /// Removes all completion callbacks for the current activity.
 785    /// </summary>
 786    public void ClearCompletionCallbacks()
 787    {
 4927788        var entriesToRemove = WorkflowExecutionContext.CompletionCallbacks.Where(x => x.Owner == this).ToList();
 3398789        WorkflowExecutionContext.RemoveCompletionCallbacks(entriesToRemove);
 3398790    }
 791
 792    public void Taint()
 793    {
 17220794        if (!IsDirty)
 3876795            IsDirty = true;
 17220796    }
 797
 798    public void ClearTaint()
 799    {
 3389800        if (IsDirty)
 3389801            IsDirty = false;
 3389802    }
 803
 804    internal void IncrementExecutionCount()
 805    {
 3287806        _executionCount++;
 3287807    }
 808
 809    private MemoryBlock? GetMemoryBlock(MemoryBlockReference locationBlockReference)
 810    {
 2412811        return ExpressionExecutionContext.TryGetBlock(locationBlockReference, out var memoryBlock) ? memoryBlock : null;
 812    }
 813
 814    void IDisposable.Dispose()
 815    {
 0816    }
 817}
 818

/home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Workflows.Core/Contexts/ActivityExecutionContext.ExecutionLogEntry.cs

#LineLine coverage
 1using Elsa.Extensions;
 2using Elsa.Workflows.Models;
 3
 4namespace Elsa.Workflows;
 5
 6public partial class ActivityExecutionContext
 7{
 8    /// <summary>
 9    /// Adds a new <see cref="WorkflowExecutionLogEntry"/> to the execution log of the current <see cref="Workflows.Work
 10    /// </summary>
 11    /// <param name="eventName">The name of the event.</param>
 12    /// <param name="message">The message of the event.</param>
 13    /// <param name="source">The source of the activity. For example, the source file name and line number in case of co
 14    /// <param name="payload">Any contextual data related to this event.</param>
 15    /// <returns>Returns the created <see cref="WorkflowExecutionLogEntry"/>.</returns>
 16    public WorkflowExecutionLogEntry AddExecutionLogEntry(string eventName, string? message = null, string? source = nul
 17    {
 676618        var logEntry = new WorkflowExecutionLogEntry(
 676619            Id,
 676620            ParentActivityExecutionContext?.Id,
 676621            Activity.Id,
 676622            Activity.Type,
 676623            Activity.Version,
 676624            Activity.Name,
 676625            NodeId,
 676626            null,
 676627            _systemClock.UtcNow,
 676628            WorkflowExecutionContext.ExecutionLogSequence++,
 676629            eventName,
 676630            message,
 676631            source ?? Activity.GetSource(),
 676632            payload);
 33
 676634        WorkflowExecutionContext.ExecutionLog.Add(logEntry);
 676635        return logEntry;
 36    }
 37}

Methods/Properties

CanCancelActivity()
CancelActivityAsync()
CancelChildActivitiesAsync()
CompleteActivityAsync()
CompleteActivityWithOutcomesAsync(System.String[])
CompleteCompositeAsync()
.ctor(System.String,Elsa.Workflows.WorkflowExecutionContext,Elsa.Workflows.ActivityExecutionContext,Elsa.Workflows.IActivity,Elsa.Workflows.Models.ActivityDescriptor,System.DateTimeOffset,System.Object,Elsa.Common.ISystemClock,System.Threading.CancellationToken)
get_Id()
get_StartedAt()
get_Tag()
get_CompletedAt()
get_IsCompleted()
get_IsExecuting()
get_AggregateFaultCount()
get_WorkflowExecutionContext()
get_ParentActivityExecutionContext()
set_ParentActivityExecutionContext(Elsa.Workflows.ActivityExecutionContext)
get_SchedulingActivityExecutionId()
get_SchedulingActivityId()
get_SchedulingWorkflowInstanceId()
get_CallStackDepth()
get_ExpressionExecutionContext()
get_Variables()
get_DynamicVariables()
get_Activity()
get_ActivityDescriptor()
get_CancellationToken()
get_Status()
set_Status(Elsa.Workflows.ActivityStatus)
EnterExecution()
TransitionTo(Elsa.Workflows.ActivityStatus)
get_Exception()
set_Exception(System.Exception)
get_Properties()
get_TransientProperties()
get_Metadata()
get_ActivityNode()
get_NodeId()
get_Children()
get_Bookmarks()
get_NewBookmarks()
get_ExecutionCount()
get_WorkflowInput()
get_ActivityInput()
get_JournalData()
get_ActivityState()
get_IsDirty()
ScheduleActivityAsync(Elsa.Workflows.IActivity,Elsa.Workflows.ActivityCompletionCallback,System.Object,System.Collections.Generic.IEnumerable`1<Elsa.Workflows.Memory.Variable>)
ScheduleActivityAsync()
ScheduleActivityAsync()
ScheduleActivityAsync()
ScheduleActivitiesAsync()
ScheduleActivities(System.Collections.Generic.IEnumerable`1<Elsa.Workflows.IActivity>,Elsa.Workflows.ActivityCompletionCallback,System.Object,System.Collections.Generic.IEnumerable`1<Elsa.Workflows.Memory.Variable>)
ScheduleActivities()
CreateBookmarks(System.Collections.Generic.IEnumerable`1<System.Object>,Elsa.Workflows.ExecuteActivityDelegate,System.Boolean,System.String)
AddBookmarks(System.Collections.Generic.IEnumerable`1<Elsa.Workflows.Models.Bookmark>)
AddBookmark(Elsa.Workflows.Models.Bookmark)
CreateBookmark(Elsa.Workflows.ExecuteActivityDelegate,System.Collections.Generic.IDictionary`2<System.String,System.String>)
CreateBookmark(System.Object,Elsa.Workflows.ExecuteActivityDelegate,System.Boolean,System.Collections.Generic.IDictionary`2<System.String,System.String>)
CreateBookmark(System.Object,System.Boolean,System.Collections.Generic.IDictionary`2<System.String,System.String>)
CreateBookmark(System.Object,System.Collections.Generic.IDictionary`2<System.String,System.String>)
CreateBookmark(Elsa.Workflows.Models.CreateBookmarkArgs)
ClearBookmarks()
GetProperty(System.String)
GetProperty(System.String,System.Func`1<T>)
SetProperty(System.String,T)
UpdateProperty(System.String,System.Func`2<T,T>)
RemoveProperty(System.String)
GetMetadata(System.String)
GetMetadata(System.String,System.Func`1<T>)
SetMetadata(System.String,T)
UpdateMetadata(System.String,System.Func`2<T,T>)
RemoveMetadata(System.String)
GetRequiredService()
GetRequiredService(System.Type)
GetOrCreateService()
GetOrCreateService(System.Type)
GetService()
GetServices()
GetService(System.Type)
Get(Elsa.Workflows.Models.Input`1<T>)
Get(Elsa.Workflows.Models.Output`1<T>)
Get(Elsa.Workflows.Models.Output)
Get(Elsa.Expressions.Models.MemoryBlockReference)
Get(Elsa.Expressions.Models.MemoryBlockReference)
TryGet(Elsa.Expressions.Models.MemoryBlockReference,System.Object&)
Set(Elsa.Expressions.Models.MemoryBlockReference,System.Object,System.Action`1<Elsa.Expressions.Models.MemoryBlock>)
Set(Elsa.Workflows.Models.Output`1<T>,T,System.String)
Set(Elsa.Workflows.Models.Output,System.Object,System.String)
ClearCompletionCallbacks()
Taint()
ClearTaint()
IncrementExecutionCount()
GetMemoryBlock(Elsa.Expressions.Models.MemoryBlockReference)
System.IDisposable.Dispose()
AddExecutionLogEntry(System.String,System.String,System.String,System.Object)