< 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    {
 270014        return Status is not ActivityStatus.Canceled and not ActivityStatus.Completed;
 15    }
 16
 17    private async Task CancelActivityAsync()
 18    {
 419        if(!CanCancelActivity())
 020            return;
 21
 422        TransitionTo(ActivityStatus.Canceled);
 423        ClearBookmarks();
 424        ClearCompletionCallbacks();
 925        WorkflowExecutionContext.Bookmarks.RemoveWhere(x => x.ActivityNodeId == NodeId);
 426        AddExecutionLogEntry("Canceled");
 427        await this.SendSignalAsync(new CancelSignal());
 428        await CancelChildActivitiesAsync();
 29
 30        // ReSharper disable once MethodSupportsCancellation
 431        await _publisher.SendAsync(new ActivityCancelled(this));
 432    }
 33
 34    private async Task CancelChildActivitiesAsync()
 35    {
 2636        var childContexts = WorkflowExecutionContext.ActivityExecutionContexts.Where(x => x.ParentActivityExecutionConte
 37
 838        foreach (var childContext in childContexts)
 039            await childContext.CancelActivityAsync();
 440    }
 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    {
 341515        var outcomes = result as Outcomes;
 16
 17        // If the activity is executing in the background, simply capture the result and return.
 341518        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.
 341528        if (Status != ActivityStatus.Running)
 729            return;
 30
 31        // Cancel any non-completed child activities.
 610432        var childContexts = Children.Where(x => x.CanCancelActivity()).ToList();
 33
 682434        foreach (var childContext in childContexts)
 435            await childContext.CancelActivityAsync();
 36
 37        // Mark the activity as complete.
 340838        TransitionTo(ActivityStatus.Completed);
 39
 40        // Record the outcomes, if any.
 340841        if (outcomes != null)
 10442            JournalData["Outcomes"] = outcomes.Names;
 43
 44        // Add an execution log entry.
 340845        AddExecutionLogEntry("Completed");
 46
 47        // Send a signal.
 340848        await this.SendSignalAsync(new ActivityCompleted(result));
 49
 50        // Clear bookmarks.
 340851        ClearBookmarks();
 344152        WorkflowExecutionContext.Bookmarks.RemoveWhere(x => x.ActivityInstanceId == Id);
 53
 54        // Remove completion callbacks.
 340855        ClearCompletionCallbacks();
 56
 57        // Remove all associated variables, unless this is the root context - in which case we want to keep the variable
 340858        if (ParentActivityExecutionContext != null)
 59        {
 275860            var variablePersistenceManager = GetRequiredService<IVariablePersistenceManager>();
 275861            await variablePersistenceManager.DeleteVariablesAsync(this);
 62        }
 63
 64        // Update the completed at timestamp.
 340865        CompletedAt = WorkflowExecutionContext.SystemClock.UtcNow;
 341566    }
 67
 68    /// <summary>
 69    /// Complete the current activity with the specified outcomes.
 70    /// </summary>
 71    public ValueTask CompleteActivityWithOutcomesAsync(params string[] outcomes)
 72    {
 9973        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.
 390327    private List<Bookmark> _newBookmarks = [];
 28
 29    /// <summary>
 30    /// Initializes a new instance of the <see cref="ActivityExecutionContext"/> class.
 31    /// </summary>
 390332    public ActivityExecutionContext(
 390333        string id,
 390334        WorkflowExecutionContext workflowExecutionContext,
 390335        ActivityExecutionContext? parentActivityExecutionContext,
 390336        IActivity activity,
 390337        ActivityDescriptor activityDescriptor,
 390338        DateTimeOffset startedAt,
 390339        object? tag,
 390340        ISystemClock systemClock,
 390341        CancellationToken cancellationToken)
 42    {
 390343        _systemClock = systemClock;
 390344        Properties = new ChangeTrackingDictionary<string, object>(Taint);
 390345        Metadata = new ChangeTrackingDictionary<string, object>(Taint);
 390346        ActivityState = new ChangeTrackingDictionary<string, object>(Taint);
 390347        ActivityInput = new ChangeTrackingDictionary<string, object>(Taint);
 390348        WorkflowExecutionContext = workflowExecutionContext;
 390349        ParentActivityExecutionContext = parentActivityExecutionContext;
 390350        var expressionExecutionContextProps = ExpressionExecutionContextExtensions.CreateActivityExecutionContextPropert
 390351        expressionExecutionContextProps[ExpressionExecutionContextExtensions.ActivityKey] = activity;
 390352        ExpressionExecutionContext = new(workflowExecutionContext.ServiceProvider, new(), parentActivityExecutionContext
 390353        Activity = activity;
 390354        ActivityDescriptor = activityDescriptor;
 390355        StartedAt = startedAt;
 390356        Status = ActivityStatus.Pending;
 390357        Tag = tag;
 390358        CancellationToken = cancellationToken;
 390359        Id = id;
 390360        _publisher = GetRequiredService<INotificationSender>();
 390361    }
 62
 63    /// <summary>
 64    /// The ID of the current activity execution context.
 65    /// </summary>
 4657066    public string Id { get; set; }
 67
 68    /// <summary>
 69    /// The time at which the activity execution context was created.
 70    /// </summary>
 818271    public DateTimeOffset StartedAt { get; set; }
 72
 73    /// <summary>
 74    /// An optional tag to associate with the activity execution.
 75    /// </summary>
 750076    public object? Tag { get; set; }
 77
 78    /// <summary>
 79    /// The time at which the activity execution context was completed.
 80    /// </summary>
 768281    public DateTimeOffset? CompletedAt { get; set; }
 82
 83    /// <summary>
 84    /// Returns true if the activity execution context has completed.
 85    /// </summary>
 1350686    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>
 747297    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>
 4361102    public int AggregateFaultCount { get; set; }
 103
 104    /// <summary>
 105    /// The workflow execution context.
 106    /// </summary>
 169175107    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    {
 62284115        get => _parentActivityExecutionContext;
 116        internal set
 117        {
 4008118            _parentActivityExecutionContext = value;
 4008119            _parentActivityExecutionContext?.Children.Add(this);
 2920120        }
 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>
 7370129    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>
 6268135    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>
 7351142    public string? SchedulingWorkflowInstanceId { get; set; }
 143
 144    /// <summary>
 145    /// The depth of this activity in the call stack (0 for root activities).
 146    /// </summary>
 9930147    public int CallStackDepth { get; set; }
 148
 149    /// <summary>
 150    /// The expression execution context.
 151    /// </summary>
 45738152    public ExpressionExecutionContext ExpressionExecutionContext { get; }
 153
 154    /// <inheritdoc />
 155    public IEnumerable<Variable> Variables
 156    {
 157        get
 158        {
 6411159            var containerVariables = (Activity as IVariableContainer)?.Variables ?? Enumerable.Empty<Variable>();
 6411160            var dynamicVariables = DynamicVariables;
 6411161            var mergedVariables = new Dictionary<string, Variable>();
 162
 13100163            foreach (var containerVariable in containerVariables)
 164            {
 139165                var name = !string.IsNullOrEmpty(containerVariable.Name) ? containerVariable.Name : containerVariable.Id
 139166                mergedVariables[name] = containerVariable;
 167            }
 168
 13192169            foreach (var dynamicVariable in dynamicVariables)
 170            {
 185171                var name = !string.IsNullOrEmpty(dynamicVariable.Name) ? dynamicVariable.Name : dynamicVariable.Id;
 185172                mergedVariables[name] = dynamicVariable;
 173            }
 6411174            return mergedVariables.Values;
 175        }
 176    }
 177
 178    /// <summary>
 179    /// A list of variables that are dynamically added to the activity execution context.
 180    /// </summary>
 11310181    public ICollection<Variable> DynamicVariables { get; set; } = new List<Variable>();
 182
 183    /// <summary>
 184    /// The currently executing activity.
 185    /// </summary>
 204116186    public IActivity Activity { get; set; }
 187
 188    /// <summary>
 189    /// The activity descriptor.
 190    /// </summary>
 26102191    public ActivityDescriptor ActivityDescriptor { get; }
 192
 193    /// <summary>
 194    /// A cancellation token to use when invoking asynchronous operations.
 195    /// </summary>
 34525196    public CancellationToken CancellationToken { get; }
 197
 198    /// <summary>
 199    /// The current status of the activity.
 200    /// </summary>
 201    public ActivityStatus Status
 202    {
 40408203        get => _status;
 204        private set
 205        {
 11189206            if (value == _status)
 3943207                return;
 208
 7246209            _status = value;
 7246210            Taint();
 7246211        }
 212    }
 213
 214    public IDisposable EnterExecution()
 215    {
 3325216        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    {
 7286224        Status = status;
 7286225    }
 226
 227    /// <summary>
 228    /// Gets or sets the exception that occurred during the activity execution, if any.
 229    /// </summary>
 230    public Exception? Exception
 231    {
 3453232        get => _exception;
 233        set
 234        {
 15235            _exception = value;
 15236            Taint();
 15237        }
 238    }
 239
 240    /// <inheritdoc />
 12936241    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>
 44701247    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>
 8237252    public IDictionary<string, object> Metadata { get; private set; }
 253
 254    /// <summary>
 255    /// Returns the <see cref="ActivityNode"/> metadata about the current activity.
 256    /// </summary>
 32007257    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
 11183263    public string NodeId => ActivityNode.NodeId;
 264
 14707265    public ISet<ActivityExecutionContext> Children { get; } = new HashSet<ActivityExecutionContext>();
 266
 267    /// <summary>
 268    /// A list of bookmarks associated with the current activity.
 269    /// </summary>
 3641270    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>
 685275    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>
 297285    public IDictionary<string, object> WorkflowInput => WorkflowExecutionContext.Input;
 286
 287    /// <summary>
 288    /// A dictionary of inputs for the current activity.
 289    /// </summary>
 7936290    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
 7499296    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>
 10565301    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>
 31449306    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    {
 2132317        var options = new ScheduleWorkOptions
 2132318        {
 2132319            CompletionCallback = completionCallback,
 2132320            Tag = tag,
 2132321            Variables = variables?.ToList()
 2132322        };
 2132323        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    {
 2968333        await ScheduleActivityAsync(activity, this, options);
 2968334    }
 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    {
 2968344        var schedulerStrategy = GetRequiredService<IActivityExecutionContextSchedulerStrategy>();
 2968345        await schedulerStrategy.ScheduleActivityAsync(this, activity, owner, options);
 2968346    }
 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    {
 7375        var options = new ScheduleWorkOptions
 7376        {
 7377            CompletionCallback = completionCallback,
 7378            Tag = tag,
 7379            Variables = variables?.ToList()
 7380        };
 7381        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    {
 42391        foreach (var activity in activities)
 14392            await ScheduleActivityAsync(activity, options);
 7393    }
 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    {
 74430        _newBookmarks.Add(bookmark);
 74431        WorkflowExecutionContext.Bookmarks.Add(bookmark);
 74432        Taint();
 74433    }
 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    {
 74507        var payload = options?.Stimulus;
 74508        var callback = options?.Callback;
 74509        var bookmarkName = options?.BookmarkName ?? Activity.Type;
 74510        var bookmarkHasher = GetRequiredService<IStimulusHasher>();
 74511        var identityGenerator = GetRequiredService<IIdentityGenerator>();
 74512        var includeActivityInstanceId = options?.IncludeActivityInstanceId ?? true;
 74513        var hash = bookmarkHasher.Hash(bookmarkName, payload, includeActivityInstanceId ? Id : null);
 74514        var bookmarkId = options?.BookmarkId ?? identityGenerator.GenerateId();
 515
 74516        var bookmark = new Bookmark(
 74517            bookmarkId,
 74518            bookmarkName,
 74519            hash,
 74520            payload,
 74521            Activity.Id,
 74522            ActivityNode.NodeId,
 74523            Id,
 74524            _systemClock.UtcNow,
 74525            options?.AutoBurn ?? true,
 74526            callback?.Method.Name,
 74527            options?.AutoComplete ?? true,
 74528            options?.Metadata);
 529
 74530        AddBookmark(bookmark);
 74531        return bookmark;
 532    }
 533
 534    /// <summary>
 535    /// Clear all bookmarks.
 536    /// </summary>
 537    public void ClearBookmarks()
 538    {
 3413539        _newBookmarks.Clear();
 3489540        WorkflowExecutionContext.Bookmarks.RemoveWhere(x => x.ActivityInstanceId == Id);
 3413541        Taint();
 3413542    }
 543
 544    /// <summary>
 545    /// Returns a property value associated with the current activity context.
 546    /// </summary>
 1421547    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>
 123566    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    {
 382573        var value = GetProperty<T?>(key);
 382574        value = updater(value);
 382575        Properties[key] = value;
 382576        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>
 33657631    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>
 3054638    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>
 266666    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>
 2860681    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    {
 2257706        return !TryGet(blockReference, out var value)
 2257707            ? throw new InvalidOperationException($"The memory block '{blockReference}' does not exist.")
 2257708            : 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    {
 2127719        var value = Get(blockReference);
 2127720        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
 2443732        var memoryBlock = GetMemoryBlock(blockReference);
 733
 2443734        if (memoryBlock != null)
 735        {
 2443736            value = memoryBlock.Value;
 2443737            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>
 1694766    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.
 1722777        ExpressionExecutionContext.Set(output, value);
 778
 779        // Also store the value in the workflow execution transient activity output register.
 1722780        WorkflowExecutionContext.RecordActivityOutput(this, outputName, value);
 1722781    }
 782
 783    /// <summary>
 784    /// Removes all completion callbacks for the current activity.
 785    /// </summary>
 786    public void ClearCompletionCallbacks()
 787    {
 4952788        var entriesToRemove = WorkflowExecutionContext.CompletionCallbacks.Where(x => x.Owner == this).ToList();
 3413789        WorkflowExecutionContext.RemoveCompletionCallbacks(entriesToRemove);
 3413790    }
 791
 792    public void Taint()
 793    {
 17318794        if (!IsDirty)
 3865795            IsDirty = true;
 17318796    }
 797
 798    public void ClearTaint()
 799    {
 3422800        if (IsDirty)
 3422801            IsDirty = false;
 3422802    }
 803
 804    internal void IncrementExecutionCount()
 805    {
 3312806        _executionCount++;
 3312807    }
 808
 809    private MemoryBlock? GetMemoryBlock(MemoryBlockReference locationBlockReference)
 810    {
 2443811        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    {
 681018        var logEntry = new WorkflowExecutionLogEntry(
 681019            Id,
 681020            ParentActivityExecutionContext?.Id,
 681021            Activity.Id,
 681022            Activity.Type,
 681023            Activity.Version,
 681024            Activity.Name,
 681025            NodeId,
 681026            null,
 681027            _systemClock.UtcNow,
 681028            WorkflowExecutionContext.ExecutionLogSequence++,
 681029            eventName,
 681030            message,
 681031            source ?? Activity.GetSource(),
 681032            payload);
 33
 681034        WorkflowExecutionContext.ExecutionLog.Add(logEntry);
 681035        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)