Beispiel #1
0
        /// <summary>
        /// Starts the correlation context.
        /// </summary>
        /// <param name="correlationId">The correlation id to create the context for.</param>
        /// <returns>The created correlation context (also accessible via <see cref="ICorrelationContextAccessor"/>), or null if diagnostics and logging is disabled.</returns>
        public CorrelationContext Start(string correlationId)
        {
            if (correlationId == null)
            {
                throw new ArgumentNullException(nameof(correlationId));
            }

            bool isDiagnosticsEnabled = _diagnosticListener?.IsEnabled() ?? false;
            bool isLoggingEnabled     = _logger.IsEnabled(LogLevel.Critical);

            if (isDiagnosticsEnabled || isLoggingEnabled)
            {
                CorrelationContext context = _correlationContextFactory.Create(correlationId);

                if (isDiagnosticsEnabled)
                {
                    // TODO: add Activity support
                    //var activity = new Activity("Correlated-Request");
                    //activity.SetParentId(correlationId);
                    //_diagnosticListener.StartActivity(activity, new {})
                }

                if (isLoggingEnabled)
                {
                    _logScope = _logger.BeginCorrelatedScope(correlationId);
                }

                _activity?.Start(context);

                return(context);
            }

            return(null);
        }
            public void When_starting_correlationContext_when_another_context_is_active_should_start_new()
            {
                const string parentContextId = nameof(parentContextId);
                const string innerContextId  = nameof(innerContextId);

                _sut.Correlate(parentContextId,
                               () =>
                {
                    CorrelationContext parentContext = _correlationContextAccessor.CorrelationContext;
                    parentContext.Should().NotBeNull();
                    parentContext.CorrelationId.Should().Be(parentContextId);

                    _sut.Correlate(innerContextId,
                                   () =>
                    {
                        CorrelationContext innerContext = _correlationContextAccessor.CorrelationContext;
                        innerContext.Should().NotBeNull();
                        innerContext.Should().NotBe(parentContext);
                        innerContext.CorrelationId.Should().Be(innerContextId);
                    });

                    _correlationContextAccessor.CorrelationContext.Should().NotBeNull();

                    _correlationContextAccessor.CorrelationContext
                    .CorrelationId
                    .Should()
                    .Be(parentContextId);
                });
            }
        private static bool HandlesException <T>(OnException onException, CorrelationContext correlationContext, Exception ex, out T result)
        {
            if (correlationContext != null && !ex.Data.Contains(CorrelateConstants.CorrelationIdKey))
            {
                // Because we're about to lose context scope, enrich exception with correlation id for reference by calling code.
                ex.Data.Add(CorrelateConstants.CorrelationIdKey, correlationContext.CorrelationId);
            }

            if (onException != null)
            {
                bool hasResultValue = typeof(T) != typeof(Void);

                // Allow caller to handle exception inline before losing context scope.
                ExceptionContext exceptionContext = hasResultValue ? new ExceptionContext <T>() : new ExceptionContext();
                exceptionContext.Exception          = ex;
                exceptionContext.CorrelationContext = correlationContext;

                onException(exceptionContext);
                if (exceptionContext.IsExceptionHandled)
                {
                    result = hasResultValue
                                                ? ((ExceptionContext <T>)exceptionContext).Result
                                                : default(T);
                    return(true);
                }
            }

            result = default(T);
            return(false);
        }
            public Task When_starting_correlationContext_with_legacy_ctor_when_another_context_is_active_should_not_throw()
            {
                const string parentContextId = nameof(parentContextId);

#pragma warning disable 618 // justification, covering legacy implementation (pre v3.0)
                var sut = new CorrelationManager(
                    new CorrelationContextFactory(_correlationContextAccessor),
                    _correlationIdFactoryMock.Object,
                    new NullLogger <CorrelationManager>()
                    );
#pragma warning restore 618

                return(sut.CorrelateAsync(parentContextId,
                                          async() =>
                {
                    CorrelationContext parentContext = _correlationContextAccessor.CorrelationContext;
                    parentContext.Should().NotBeNull();
                    parentContext.CorrelationId.Should().Be(parentContextId);

                    await sut.CorrelateAsync(() =>
                    {
                        CorrelationContext innerContext = _correlationContextAccessor.CorrelationContext;
                        innerContext.Should().NotBeNull().And.NotBe(parentContext);
                        innerContext.CorrelationId.Should().NotBe(parentContextId);

                        return Task.CompletedTask;
                    });
                }));
            }
            public Task When_starting_correlationContext_when_another_context_is_active_should_start_new()
            {
                const string parentContextId = nameof(parentContextId);
                const string innerContextId  = nameof(innerContextId);

                return(_sut.CorrelateAsync(parentContextId,
                                           async() =>
                {
                    CorrelationContext parentContext = _correlationContextAccessor.CorrelationContext;
                    parentContext.Should().NotBeNull();
                    parentContext.CorrelationId.Should().Be(parentContextId);

                    await _sut.CorrelateAsync(innerContextId,
                                              () =>
                    {
                        CorrelationContext innerContext = _correlationContextAccessor.CorrelationContext;
                        innerContext.Should().NotBeNull();
                        innerContext.Should().NotBe(parentContext);
                        innerContext.CorrelationId.Should().Be(innerContextId);

                        return Task.CompletedTask;
                    });

                    _correlationContextAccessor.CorrelationContext.Should().NotBeNull();

                    _correlationContextAccessor.CorrelationContext
                    .CorrelationId
                    .Should()
                    .Be(parentContextId);
                }));
            }
        private async Task CorrelateAsync(string correlationId, RootActivity activity, Func <Task> correlatedTask, OnException onException)
        {
            CorrelationContext correlationContext = activity.Start(correlationId ?? _correlationIdFactory.Create());

            try
            {
                await correlatedTask().ConfigureAwait(false);
            }
            catch (Exception ex)
            {
                if (correlationContext != null && !ex.Data.Contains(CorrelateConstants.CorrelationIdKey))
                {
                    // Because we're about to lose context scope, enrich exception with correlation id for reference by calling code.
                    ex.Data.Add(CorrelateConstants.CorrelationIdKey, correlationContext.CorrelationId);
                }

                if (onException == null)
                {
                    throw;
                }

                // Allow caller to handle exception inline before losing context scope.
                bool isHandled = onException(correlationContext, ex);
                if (!isHandled)
                {
                    throw;
                }
            }
            finally
            {
                activity.Stop();
            }
        }
Beispiel #7
0
        public async Task When_running_multiple_tasks_in_nested_context_should_inherit_from_ambient_parent()
        {
            const string rootName = "root-context";
            var          expectedNestedCorrelationIds = new List <string>
            {
                $"{rootName} > 1:0 | 1:0 > 1:1 | 1:1 > 1:2 | 1:2 > 1:3 | ",
                $"{rootName} > 2:0 | 2:0 > 2:1 | 2:1 > 2:2 | 2:2 > 2:3 | ",
                $"{rootName} > 3:0 | 3:0 > 3:1 | 3:1 > 3:2 | 3:2 > 3:3 | "
            };

            var rootContext = new CorrelationContext
            {
                CorrelationId = rootName
            };

            _sut.CorrelationContext = rootContext;

            // Act
            IEnumerable <Task <string> > tasks = Enumerable.Range(1, 3)
                                                 .Select(i => RunChildTask(i.ToString()));

            string[] actual = await Task.WhenAll(tasks);

            _sut.CorrelationContext = null;

            // Assert
            actual.Should().BeEquivalentTo(expectedNestedCorrelationIds, "each task that creates new context should inherit from parent, and all inner tasks from their respective parent");
            _sut.CorrelationContext.Should().BeNull();
        }
Beispiel #8
0
        /// <inheritdoc />
        CorrelationContext ICorrelationContextFactory.Create(string correlationId)
        {
            CorrelationContext correlationContext = Create(correlationId);

            if (_correlationContextAccessor != null)
            {
                _correlationContextAccessor.CorrelationContext = correlationContext;
            }

            return(correlationContext);
        }
            public void When_starting_correlationContext_inside_running_context_without_specifying_should_reuse()
            {
                _sut.Correlate(() =>
                {
                    CorrelationContext parentContext = _correlationContextAccessor.CorrelationContext;

                    _sut.Correlate(() =>
                    {
                        CorrelationContext innerContext = _correlationContextAccessor.CorrelationContext;
                        innerContext.Should()
                        .NotBe(parentContext)
                        .And.BeEquivalentTo(parentContext);
                    });
                });
            }
            public Task When_starting_correlationContext_inside_running_context_without_specifying_should_reuse()
            {
                return(_sut.CorrelateAsync(async() =>
                {
                    CorrelationContext parentContext = _correlationContextAccessor.CorrelationContext;

                    await _sut.CorrelateAsync(() =>
                    {
                        CorrelationContext innerContext = _correlationContextAccessor.CorrelationContext;
                        innerContext.Should()
                        .NotBe(parentContext)
                        .And.BeEquivalentTo(parentContext);

                        return Task.CompletedTask;
                    });
                }));
            }
        private T Execute <T>(string correlationId, Func <T> correlatedFunc, OnException onException)
        {
            IActivity          activity           = CreateActivity();
            CorrelationContext correlationContext = StartActivity(correlationId, activity);

            try
            {
                return(correlatedFunc());
            }
            catch (Exception ex) when(HandlesException(onException, correlationContext, ex, out T exceptionResult))
            {
                return(exceptionResult);
            }
            finally
            {
                activity.Stop();
            }
        }
        private async Task <T> ExecuteAsync <T>(string correlationId, Func <Task <T> > correlatedTask, OnException onException)
        {
            IActivity          activity           = CreateActivity();
            CorrelationContext correlationContext = StartActivity(correlationId, activity);

            try
            {
                return(await correlatedTask().ConfigureAwait(false));
            }
            catch (Exception ex) when(HandlesException(onException, correlationContext, ex, out T exceptionResult))
            {
                return(exceptionResult);
            }
            finally
            {
                activity.Stop();
            }
        }
Beispiel #13
0
 internal ExceptionContext(CorrelationContext correlationContext, Exception exception)
 {
     CorrelationContext = correlationContext;
     Exception          = exception;
 }
Beispiel #14
0
 void IActivity.Start(CorrelationContext correlationContext)
 {
     throw new NotImplementedException();
 }