/// <summary>
        /// Adds the action with the given type to the collection.
        /// </summary>
        /// <param name="actionType">The type of the action.</param>
        /// <param name="priority">The priority of the action. Actions with a lower value will be executed first. Note that this only affects actions which are independent from each other.</param>
        public void AddAction(Type actionType, int priority = 0)
        {
            var actionInfo = ActionActivator.GetActionInfo(actionType);

            var indexToInsert = _actions.Count;

            for (int i = _actions.Count - 1; i >= 0; i--)
            {
                if (_actions[i].Priority <= priority)
                {
                    break;
                }

                indexToInsert = i;
            }

            _actions.Insert(indexToInsert, new ActionCollectionEntry(actionInfo, priority));
        }
Beispiel #2
0
        public async Task ExecuteAsync(T context)
        {
            // Check whether the target wants to be able to trace which actions were executed on it
            var trace = context is IActionTracingContainer atc ? atc.ActionTrace : null;

            try
            {
                trace?.AddEvent(ActionTraceEvent.Begin, ToString());

                foreach (var curItem in _items)
                {
                    if (curItem == null)
                    {
                        continue;
                    }

                    // Build the action-identifier for tracing
                    var actionIdentifier = trace == null
                        ? null
                        : curItem.ActionContext.Name + (curItem.ActionContext.Description == null ? null : $"({curItem.ActionContext.Description})");

                    try
                    {
                        trace?.AddEvent(ActionTraceEvent.Begin, actionIdentifier);

                        IAction <T> instance = null;
                        try
                        {
                            // Create the actual instance of the action
                            instance = (IAction <T>)ActionActivator.CreateInstance(
                                curItem.ActionInfo,
                                curItem.ServiceProvider,
                                curItem.ExportProvider);

                            await instance.ExecuteAsync(context, _cancellationToken);
                        }
                        finally
                        {
                            try
                            {
                                if (instance is IDisposable d)
                                {
                                    d.Dispose();
                                }

#if (NETSTANDARD2_1 || NET)
                                if (instance is IAsyncDisposable ad)
                                {
                                    await ad.DisposeAsync();
                                }
#endif
                            }
                            catch (Exception ex)
                            {
                                throw new ActionException($"An unexpected exception occured during disposing action of type \"{instance.GetType().FullName}\".", ex, curItem.ActionInfo);
                            }
                        }

                        // Add all exports to the global export-provider when the action finished successfully
                        // -> If the action would throw an exception we don't want to add already exported objects to it
                        foreach (var curExport in curItem.ActionContext.ExportProvider)
                        {
                            if (!curItem.ExportProvider.TryExport(curExport.Type, curExport.Name, curExport.Value))
                            {
                                throw new InvalidOperationException($"An object of type \"{curExport.Type.FullName}\" with name \"{curExport.Name}\" was already exported.");
                            }
                        }

                        trace?.AddEvent(ActionTraceEvent.End, actionIdentifier);
                    }
                    catch (Exception ex)
                    {
                        trace?.AddEvent(ActionTraceEvent.UnexpectedEnd, actionIdentifier, ex);

                        if (ex is ActionException)
                        {
                            throw;
                        }
                    }
                }

                trace?.AddEvent(ActionTraceEvent.End, ToString());
            }
            catch (Exception ex)
            {
                trace?.AddEvent(ActionTraceEvent.UnexpectedEnd, ToString(), ex);

                if (ex is ActionException)
                {
                    throw;
                }
            }
        }