/** * Add {@link HystrixCommand} instance to the request log. * * @param command * {@code HystrixCommand<?>} */ internal void AddExecutedCommand(HystrixCommand command) { if (!executedCommands.Offer(command)) { // see RequestLog: Reduce Chance of Memory Leak https://github.com/Netflix/Hystrix/issues/53 logger.Warn("RequestLog ignoring command after reaching limit of " + MaxStorage + ". See https://github.com/Netflix/Hystrix/issues/53 for more information."); } }
public void TestStreamHasData() { var commandShowsUp = new AtomicBoolean(false); var threadPoolShowsUp = new AtomicBoolean(false); var latch = new CountdownEvent(1); var num = 10; for (var i = 0; i < 2; i++) { HystrixCommand <int> cmd = Command.From(GroupKey, CommandKey, HystrixEventType.SUCCESS, 50); cmd.Observe(); } stream.Observe().Take(num).Subscribe( (utilization) => { output.WriteLine(Time.CurrentTimeMillis + " : Received data with : " + " : Received data with : " + utilization.CommandUtilizationMap.Count + " commands"); if (utilization.CommandUtilizationMap.ContainsKey(CommandKey)) { commandShowsUp.Value = true; } if (utilization.ThreadPoolUtilizationMap.Count != 0) { threadPoolShowsUp.Value = true; } }, (e) => { output.WriteLine(Time.CurrentTimeMillis + " : " + Thread.CurrentThread.ManagedThreadId + " OnError : " + e); latch.SignalEx(); }, () => { output.WriteLine(Time.CurrentTimeMillis + " : " + Thread.CurrentThread.ManagedThreadId + " OnCompleted"); latch.SignalEx(); }); Assert.True(latch.Wait(10000), "CountdownEvent was not set!"); Assert.True(commandShowsUp.Value); Assert.True(threadPoolShowsUp.Value); }
public void TestStreamHasData() { AtomicBoolean commandShowsUp = new AtomicBoolean(false); AtomicBoolean threadPoolShowsUp = new AtomicBoolean(false); CountdownEvent latch = new CountdownEvent(1); int num = 10; for (int i = 0; i < 2; i++) { HystrixCommand <int> cmd = Command.From(GroupKey, CommandKey, HystrixEventType.SUCCESS, 50); cmd.Observe(); } stream.Observe().Take(num).Subscribe( (configuration) => { output.WriteLine((DateTime.Now.Ticks / 10000) + " : " + Thread.CurrentThread.ManagedThreadId + " : Received data with : " + configuration.CommandConfig.Count + " commands"); if (configuration.CommandConfig.ContainsKey(CommandKey)) { commandShowsUp.Value = true; } if (configuration.ThreadPoolConfig.Count != 0) { threadPoolShowsUp.Value = true; } }, (e) => { output.WriteLine((DateTime.Now.Ticks / 10000) + " : " + Thread.CurrentThread.ManagedThreadId + " OnError : " + e); latch.SignalEx(); }, () => { output.WriteLine((DateTime.Now.Ticks / 10000) + " : " + Thread.CurrentThread.ManagedThreadId + " OnCompleted"); latch.SignalEx(); }); Assert.True(latch.Wait(10000)); Assert.True(commandShowsUp.Value); Assert.True(threadPoolShowsUp.Value); }
public void TestStreamHasData() { AtomicBoolean commandShowsUp = new AtomicBoolean(false); CountdownEvent latch = new CountdownEvent(1); int NUM = 10; for (int i = 0; i < 2; i++) { HystrixCommand <int> cmd = Command.From(groupKey, commandKey, HystrixEventType.SUCCESS, 50); cmd.Observe(); } stream.Observe().Take(NUM).Subscribe( (dashboardData) => { output.WriteLine(DateTime.Now.Ticks / 10000 + " : Received data with : " + dashboardData.commandMetrics.Count + " commands"); foreach (HystrixCommandMetrics metrics in dashboardData.commandMetrics) { if (metrics.CommandKey.Equals(commandKey)) { commandShowsUp.Value = true; } } }, (e) => { output.WriteLine(DateTime.Now.Ticks / 10000 + " : " + Thread.CurrentThread.ManagedThreadId + " OnError : " + e); }, () => { output.WriteLine(DateTime.Now.Ticks / 10000 + " : " + Thread.CurrentThread.ManagedThreadId + " OnCompleted"); latch.SignalEx(); }); Assert.True(latch.Wait(10000)); Assert.True(commandShowsUp.Value); }
public void TestStreamHasData() { var commandShowsUp = new AtomicBoolean(false); var latch = new CountdownEvent(1); var num = 10; for (var i = 0; i < 2; i++) { HystrixCommand <int> cmd = Command.From(GroupKey, CommandKey, HystrixEventType.SUCCESS, 50); cmd.Observe(); } stream.Observe().Take(num).Subscribe( (dashboardData) => { output.WriteLine(Time.CurrentTimeMillis + " : Received data with : " + dashboardData.CommandMetrics.Count + " commands"); foreach (var metrics in dashboardData.CommandMetrics) { if (metrics.CommandKey.Equals(CommandKey)) { commandShowsUp.Value = true; } } }, (e) => { output.WriteLine(Time.CurrentTimeMillis + " : " + Thread.CurrentThread.ManagedThreadId + " OnError : " + e); }, () => { output.WriteLine(Time.CurrentTimeMillis + " : " + Thread.CurrentThread.ManagedThreadId + " OnCompleted"); latch.SignalEx(); }); Assert.True(latch.Wait(10000), "CountdownEvent was not set!"); Assert.True(commandShowsUp.Value); }
public async Task <IActionResult> CircuitBreaker() { var cmd = new HystrixCommand <string>(HystrixCommandGroupKeyDefault.AsKey("fancyCommand"), () => { if (_appState.IsFaulted) { throw new Exception("Failing miserably"); } Thread.Sleep(_appState.Timeout); return("I'm working fine"); }, () => "We'll be back soon"); var result = await cmd.ExecuteAsync(); _log.LogInformation($"IsSuccessfulExecution: {cmd.IsSuccessfulExecution}"); _log.LogInformation($"IsCircuitBreakerOpen: {cmd.IsCircuitBreakerOpen}"); _log.LogInformation($"IsResponseShortCircuited: {cmd.IsResponseShortCircuited}"); _log.LogInformation($"IsExecutionComplete: {cmd.IsExecutionComplete}"); _log.LogInformation($"IsFailedExecution: {cmd.IsFailedExecution}"); _log.LogInformation($"IsResponseRejected: {cmd.IsResponseRejected}"); _log.LogInformation($"IsResponseTimedOut: {cmd.IsResponseTimedOut}"); return(View("Hystrix", (result, cmd, _appState))); }
public virtual T OnFallbackSuccess <T>(HystrixCommand <T> commandInstance, T fallbackResponse) { // pass-thru by default return(fallbackResponse); }
public void ExecuteBatchIfNotAlreadyStarted() { /* * - check that we only execute once since there's multiple paths to do so (timer, waiting thread or max batch size hit) * - close the gate so 'offer' can no longer be invoked and we turn those threads away so they create a new batch */ if (batchStarted.CompareAndSet(false, true)) { /* wait for 'offer'/'remove' threads to finish before executing the batch so 'requests' is complete */ batchLock.EnterWriteLock(); List <CollapsedRequest <RequestResponseType, RequestArgumentType> > args = new List <CollapsedRequest <RequestResponseType, RequestArgumentType> >(); try { // Check for cancel foreach (var entry in argumentMap) { if (!entry.Value.IsRequestCanceled()) { args.Add(entry.Value); } } // Handle case of null arg submit if (nullArg.Value != null) { var req = nullArg.Value; if (!req.IsRequestCanceled()) { args.Add(req); } } if (args.Count > 0) { // shard batches ICollection <ICollection <ICollapsedRequest <RequestResponseType, RequestArgumentType> > > shards = commandCollapser.DoShardRequests(args); // for each shard execute its requests foreach (ICollection <ICollapsedRequest <RequestResponseType, RequestArgumentType> > shardRequests in shards) { try { // create a new command to handle this batch of requests HystrixCommand <BatchReturnType> command = commandCollapser.DoCreateObservableCommand(shardRequests); BatchReturnType result = command.Execute(); try { commandCollapser.DoMapResponseToRequests(result, shardRequests); } catch (Exception mapException) { // logger.debug("Exception mapping responses to requests.", e); foreach (CollapsedRequest <RequestResponseType, RequestArgumentType> request in args) { try { request.SetExceptionIfResponseNotReceived(mapException); } catch (InvalidOperationException) { // if we have partial responses set in mapResponseToRequests // then we may get InvalidOperationException as we loop over them // so we'll log but continue to the rest // logger.error("Partial success of 'mapResponseToRequests' resulted in InvalidOperationException while setting Exception. Continuing ... ", e2); } } } // check that all requests had setResponse or setException invoked in case 'mapResponseToRequests' was implemented poorly Exception e = null; foreach (var request in shardRequests.OfType <CollapsedRequest <RequestResponseType, RequestArgumentType> >()) { try { e = request.SetExceptionIfResponseNotReceived(e, "No response set by " + commandCollapser.CollapserKey.Name + " 'mapResponseToRequests' implementation."); } catch (InvalidOperationException) { // logger.debug("Partial success of 'mapResponseToRequests' resulted in InvalidOperationException while setting 'No response set' Exception. Continuing ... ", e2); } } } catch (Exception e) { // logger.error("Exception while creating and queueing command with batch.", e); // if a failure occurs we want to pass that exception to all of the Futures that we've returned foreach (var request in shardRequests.OfType <CollapsedRequest <RequestResponseType, RequestArgumentType> >()) { try { request.Exception = e; } catch (InvalidOperationException) { // logger.debug("Failed trying to setException on CollapsedRequest", e2); } } } } } } catch (Exception e) { // logger.error("Exception while sharding requests.", e); // same error handling as we do around the shards, but this is a wider net in case the shardRequest method fails foreach (ICollapsedRequest <RequestResponseType, RequestArgumentType> request in args) { try { request.Exception = e; } catch (InvalidOperationException) { // logger.debug("Failed trying to setException on CollapsedRequest", e2); } } } finally { batchLock.ExitWriteLock(); } } }
public override void OnFallbackStart <T>(HystrixCommand <T> commandInstance) { this.startFallback.IncrementAndGet(); base.OnFallbackStart(commandInstance); }
public override T OnRunSuccess <T>(HystrixCommand <T> commandInstance, T response) { this.runSuccessResponse = response; return(base.OnRunSuccess(commandInstance, response)); }
public override Exception OnError <T>(HystrixCommand <T> commandInstance, FailureType failureType, Exception e) { this.endExecuteFailureException = e; this.endExecuteFailureType = failureType; return(base.OnError(commandInstance, failureType, e)); }
public override void OnThreadComplete <T>(HystrixCommand <T> commandInstance) { this.threadComplete.IncrementAndGet(); base.OnThreadComplete(commandInstance); }
public void TestTwoSubscribersOneUnsubscribes() { CountdownEvent latch1 = new CountdownEvent(1); CountdownEvent latch2 = new CountdownEvent(1); AtomicInteger payloads1 = new AtomicInteger(0); AtomicInteger payloads2 = new AtomicInteger(0); IDisposable s1 = stream .Observe() .Take(100) .OnDispose(() => { latch1.SignalEx(); }) .Subscribe( (dashboardData) => { output.WriteLine(Time.CurrentTimeMillis + " : " + Thread.CurrentThread.ManagedThreadId + " : Dashboard 1 OnNext : " + dashboardData); payloads1.IncrementAndGet(); }, (e) => { output.WriteLine(Time.CurrentTimeMillis + " : " + Thread.CurrentThread.ManagedThreadId + " : Dashboard 1 OnError : " + e); latch1.SignalEx(); }, () => { output.WriteLine(Time.CurrentTimeMillis + " : " + Thread.CurrentThread.ManagedThreadId + " : Dashboard 1 OnCompleted"); latch1.SignalEx(); }); IDisposable s2 = stream .Observe() .Take(100) .OnDispose(() => { latch2.SignalEx(); }) .Subscribe( (dashboardData) => { output.WriteLine(Time.CurrentTimeMillis + " : " + Thread.CurrentThread.ManagedThreadId + " : Dashboard 2 OnNext : " + dashboardData); payloads2.IncrementAndGet(); }, (e) => { output.WriteLine(Time.CurrentTimeMillis + " : " + Thread.CurrentThread.ManagedThreadId + " : Dashboard 2 OnError : " + e); latch2.SignalEx(); }, () => { output.WriteLine(Time.CurrentTimeMillis + " : " + Thread.CurrentThread.ManagedThreadId + " : Dashboard 2 OnCompleted"); latch2.SignalEx(); }); // execute 1 command, then unsubscribe from first stream. then execute the rest for (int i = 0; i < 50; i++) { HystrixCommand <int> cmd = Command.From(GroupKey, CommandKey, HystrixEventType.SUCCESS, 50); cmd.Execute(); if (i == 1) { s1.Dispose(); } } Assert.True(latch1.Wait(10000)); Assert.True(latch2.Wait(10000)); output.WriteLine("s1 got : " + payloads1.Value + ", s2 got : " + payloads2.Value); Assert.True(payloads1.Value > 0); // "s1 got data" Assert.True(payloads2.Value > 0); // "s2 got data" Assert.True(payloads2.Value > payloads1.Value); // "s1 got less data than s2", }
public void TestTwoSubscribersOneUnsubscribes() { IHystrixCommandKey key = HystrixCommandKeyDefault.AsKey("CMD-Health-O"); stream = HealthCountsStream.GetInstance(key, 10, 100); CountdownEvent latch1 = new CountdownEvent(1); CountdownEvent latch2 = new CountdownEvent(1); AtomicInteger healthCounts1 = new AtomicInteger(0); AtomicInteger healthCounts2 = new AtomicInteger(0); IDisposable s1 = stream .Observe() .Take(10) .ObserveOn(TaskPoolScheduler.Default) .Finally(() => { latch1.SignalEx(); }) .Subscribe( (healthCounts) => { output.WriteLine((DateTime.Now.Ticks / 10000) + " : " + Thread.CurrentThread.ManagedThreadId + " : Health 1 OnNext : " + healthCounts); healthCounts1.IncrementAndGet(); }, (e) => { output.WriteLine((DateTime.Now.Ticks / 10000) + " : " + Thread.CurrentThread.ManagedThreadId + " : Health 1 OnError : " + e); latch1.SignalEx(); }, () => { output.WriteLine((DateTime.Now.Ticks / 10000) + " : " + Thread.CurrentThread.ManagedThreadId + " : Health 1 OnCompleted"); latch1.SignalEx(); }); IDisposable s2 = stream .Observe() .Take(10) .ObserveOn(TaskPoolScheduler.Default) .Finally(() => { latch2.SignalEx(); }) .Subscribe( (healthCounts) => { output.WriteLine((DateTime.Now.Ticks / 10000) + " : " + Thread.CurrentThread.ManagedThreadId + " : Health 2 OnNext : " + healthCounts + " : " + healthCounts2.Value); healthCounts2.IncrementAndGet(); }, (e) => { output.WriteLine((DateTime.Now.Ticks / 10000) + " : " + Thread.CurrentThread.ManagedThreadId + " : Health 2 OnError : " + e); latch2.SignalEx(); }, () => { output.WriteLine((DateTime.Now.Ticks / 10000) + " : " + Thread.CurrentThread.ManagedThreadId + " : Health 2 OnCompleted"); latch2.SignalEx(); }); // execute 5 commands, then unsubscribe from first stream. then execute the rest for (int i = 0; i < 10; i++) { HystrixCommand <int> cmd = Command.From(groupKey, key, HystrixEventType.SUCCESS, 20); cmd.Execute(); if (i == 5) { s1.Dispose(); } } Assert.True(stream.IsSourceCurrentlySubscribed); // only 1/2 subscriptions has been cancelled Assert.True(latch1.Wait(10000)); Assert.True(latch2.Wait(10000)); output.WriteLine("s1 got : " + healthCounts1.Value + ", s2 got : " + healthCounts2.Value); Assert.True(healthCounts1.Value > 0); Assert.True(healthCounts2.Value > 0); Assert.True(healthCounts2.Value > healthCounts1.Value); }
public string GetMessage(string billboardId) { var cmd = new HystrixCommand <string>(HystrixCommandGroupKeyDefault.AsKey("GetMessage"), () => RunGetMessage(billboardId), DefaultMessage); return(cmd.Execute()); }
public CachedFuture(HystrixCommand <R> command, ICommandFuture <R> commandFuture) { this.command = command; this.commandFuture = commandFuture; }
public void TestTwoSubscribersOneSlowOneFast() { CountdownEvent latch = new CountdownEvent(1); AtomicBoolean foundError = new AtomicBoolean(false); IObservable <HystrixUtilization> fast = stream .Observe() .ObserveOn(NewThreadScheduler.Default); IObservable <HystrixUtilization> slow = stream .Observe() .ObserveOn(NewThreadScheduler.Default) .Map((util) => { try { Time.Wait(100); return(util); } catch (Exception) { return(util); } }); IObservable <bool> checkZippedEqual = Observable.Zip(fast, slow, (payload, payload2) => { return(payload == payload2); }); IDisposable s1 = checkZippedEqual .Take(10000) .Subscribe( (b) => { output.WriteLine(DateTime.Now.Ticks / 10000 + " : " + Thread.CurrentThread.ManagedThreadId + " : OnNext : " + b); }, (e) => { output.WriteLine(DateTime.Now.Ticks / 10000 + " : " + Thread.CurrentThread.ManagedThreadId + " OnError : " + e); output.WriteLine(e.ToString()); foundError.Value = true; latch.SignalEx(); }, () => { output.WriteLine(DateTime.Now.Ticks / 10000 + " : " + Thread.CurrentThread.ManagedThreadId + " OnCompleted"); latch.SignalEx(); }); for (int i = 0; i < 50; i++) { HystrixCommand <int> cmd = Command.From(groupKey, commandKey, HystrixEventType.SUCCESS, 50); cmd.Execute(); } latch.Wait(10000); Assert.False(foundError.Value); s1.Dispose(); }
public void TestTwoSubscribersBothUnsubscribe() { CountdownEvent latch1 = new CountdownEvent(1); CountdownEvent latch2 = new CountdownEvent(1); AtomicInteger payloads1 = new AtomicInteger(0); AtomicInteger payloads2 = new AtomicInteger(0); IDisposable s1 = stream .Observe() .Take(10) .OnDispose(() => { latch1.SignalEx(); }) .Subscribe( (dashboardData) => { output.WriteLine(Time.CurrentTimeMillis + " : " + Thread.CurrentThread.ManagedThreadId + " : Dashboard 1 OnNext : " + dashboardData); payloads1.IncrementAndGet(); }, (e) => { output.WriteLine(Time.CurrentTimeMillis + " : " + Thread.CurrentThread.ManagedThreadId + " : Dashboard 1 OnError : " + e); latch1.SignalEx(); }, () => { output.WriteLine(Time.CurrentTimeMillis + " : " + Thread.CurrentThread.ManagedThreadId + " : Dashboard 1 OnCompleted"); latch1.SignalEx(); }); IDisposable s2 = stream .Observe() .Take(10) .OnDispose(() => { latch2.SignalEx(); }) .Subscribe( (dashboardData) => { output.WriteLine(Time.CurrentTimeMillis + " : " + Thread.CurrentThread.ManagedThreadId + " : Dashboard 2 OnNext : " + dashboardData); payloads2.IncrementAndGet(); }, (e) => { output.WriteLine(Time.CurrentTimeMillis + " : " + Thread.CurrentThread.ManagedThreadId + " : Dashboard 2 OnError : " + e); latch2.SignalEx(); }, () => { output.WriteLine(Time.CurrentTimeMillis + " : " + Thread.CurrentThread.ManagedThreadId + " : Dashboard 2 OnCompleted"); latch2.SignalEx(); }); // execute half the commands, then unsubscribe from both streams, then execute the rest for (int i = 0; i < 50; i++) { HystrixCommand <int> cmd = Command.From(GroupKey, CommandKey, HystrixEventType.SUCCESS, 50); cmd.Execute(); if (i == 25) { s1.Dispose(); s2.Dispose(); } } Assert.False(stream.IsSourceCurrentlySubscribed); // both subscriptions have been cancelled - source should be too Assert.True(latch1.Wait(10000)); Assert.True(latch2.Wait(10000)); output.WriteLine("s1 got : " + payloads1.Value + ", s2 got : " + payloads2.Value); Assert.True(payloads1.Value > 0); // "s1 got data", Assert.True(payloads2.Value > 0); // "s2 got data", }
public virtual Exception OnFallbackError <T>(HystrixCommand <T> commandInstance, Exception e) { // pass-thru by default return(e); }
public override void OnThreadStart <T>(HystrixCommand <T> commandInstance) { this.threadStart.IncrementAndGet(); base.OnThreadStart(commandInstance); }
public virtual void OnStart <T>(HystrixCommand <T> commandInstance) { // do nothing by default }
public override T OnComplete <T>(HystrixCommand <T> commandInstance, T response) { this.endExecuteSuccessResponse = response; return(base.OnComplete(commandInstance, response)); }
public virtual T OnComplete <T>(HystrixCommand <T> commandInstance, T response) { // pass-thru by default return(response); }
public override void OnRunStart <T>(HystrixCommand <T> commandInstance) { this.startRun.IncrementAndGet(); base.OnRunStart(commandInstance); }
public virtual Exception OnError <T>(HystrixCommand <T> commandInstance, FailureType failureType, Exception e) { // pass-thru by default return(e); }
public override Exception OnRunError <T>(HystrixCommand <T> commandInstance, Exception e) { this.runFailureException = e; return(base.OnRunError(commandInstance, e)); }
public virtual void OnThreadComplete <T>(HystrixCommand <T> commandInstance) { // do nothing by default }
public SemaphoreQueuedWrapperFuture(Reference <T> value, CountdownEvent executionCompleted, HystrixCommand <T> command) { this.value = value; this.executionCompleted = executionCompleted; this.command = command; }
public void Add(Type serviceType, MethodInfo mi, Type requestType, Type responseType, bool isAsync) { this.RequestTypes.Add(requestType); object[] methodCustomAttributes = mi.GetCustomAttributes(true); object[] classCustomAttributes = serviceType.GetCustomAttributes(true); var restrictTo = methodCustomAttributes.OfType <RestrictAttribute>().FirstOrDefault() ?? classCustomAttributes.OfType <RestrictAttribute>().FirstOrDefault(); var operation = new Operation { Name = mi.Name, Key = string.Format("{0}.{1}", this.RefinedFullServiceName, mi.Name.ToLower()), ServiceType = serviceType, Method = mi, RequestType = requestType, ResponseType = responseType, RestrictTo = restrictTo, Routes = new List <RestPath>(), Descritpion = mi.GetDescription(), IsAsync = isAsync, }; var hystrixCommandPropertiesSetter = new HystrixCommandPropertiesSetter(); hystrixCommandPropertiesSetter.WithCircuitBreakerForceClosed(CircuitBreakerForceClosed); // operation timeout attribute override var hystrixAttribute = methodCustomAttributes.OfType <HystrixAttribute>().FirstOrDefault(); if (hystrixAttribute != null && hystrixAttribute.Timeout > 0) { hystrixCommandPropertiesSetter.WithExecutionIsolationThreadTimeoutInMilliseconds(hystrixAttribute.Timeout); Log.Info(string.Format("Timeout for operation {0} is overridden by attribute to value {1}", mi.Name, hystrixAttribute.Timeout), new Dictionary <string, string>() { { "ErrorCode", "FXD300046" } }); } // operation timeout setting override in appSettings if (OperationTimeoutMap != null && OperationTimeoutMap.ContainsKey(mi.Name)) { var timeoutSetting = OperationTimeoutMap[mi.Name]; try { var timeout = int.Parse(timeoutSetting); if (timeout > 0) { hystrixCommandPropertiesSetter.WithExecutionIsolationThreadTimeoutInMilliseconds(timeout); Log.Info(string.Format("Timeout for operation {0} is overridden in appSettings to value {1}", mi.Name, timeout), new Dictionary <string, string>() { { "ErrorCode", "FXD300047" } }); } else { Log.Error( string.Format("Invalid operation timeout setting {0}:{1} in appSettings", mi.Name, timeoutSetting), new Dictionary <string, string>() { { "ErrorCode", "FXD300006" } }); } } catch (Exception ex) { Log.Error( string.Format("Invalid operation timeout setting {0}:{1} in appSettings", mi.Name, timeoutSetting), ex, new Dictionary <string, string>() { { "ErrorCode", "FXD300006" } }); } } var hystrixCommnad = new HystrixCommand(ServicePath, mi.Name, ServiceName, FullServiceName, ServiceMetricPrefix, hystrixCommandPropertiesSetter); operation.HystrixCommand = hystrixCommnad; operation.RequestFilters = methodCustomAttributes.OfType <IHasRequestFilter>().ToList(); operation.RequestFilters.AddRange(classCustomAttributes.OfType <IHasRequestFilter>().ToList()); operation.ResponseFilters = methodCustomAttributes.OfType <IHasResponseFilter>().ToList(); operation.ResponseFilters.AddRange(classCustomAttributes.OfType <IHasResponseFilter>().ToList()); var sensitivityAttribute = methodCustomAttributes.OfType <MessageSensitivityAttribute>().FirstOrDefault(); operation.OperationMessageLogConfig = AttributeToConfig(sensitivityAttribute); this.OperationNameMap[mi.Name.ToLower()] = operation; if (responseType != null) { this.ResponseTypes.Add(responseType); } }