private static void ThrowIfNullSubscriptionFilter(SubscriptionFilter subscriptionFilter)
 {
     if (subscriptionFilter is null)
     {
         throw new ArgumentNullException(nameof(subscriptionFilter));
     }
 }
        public void AddMessageSubscriptionAddsAMessageSubscription()
        {
            var subscriptionFilter = new SubscriptionFilter
            {
                Label             = nameof(AircraftLanded),
                MessageProperties = new Dictionary <string, string>
                {
                    { "AircraftType", "Commercial" }
                }
            };

            subscriptionFilter.Build(new(), typeof(AircraftLanded));

            var sut = new MessageHandlerResolver(new ServiceCollection());

            sut.SubcribeToMessage <AircraftTakenOff, AircraftTakenOffHandler>(BuildSubscriptionFilter <AircraftTakenOff>());
            sut.SubcribeToMessage <AircraftLanded, AircraftLandedHandler>(subscriptionFilter);
            var messageSubscriptions = sut.GetMessageHandlerMappings();

            Assert.Equal(2, messageSubscriptions.Count());
            Assert.Single(messageSubscriptions.Where(m => m.MessageHandlerType == typeof(AircraftLandedHandler)));
            Assert.Single(messageSubscriptions.Where(m => m.MessageHandlerType == typeof(AircraftTakenOffHandler)));
            Assert.Equal(subscriptionFilter.MessageProperties, messageSubscriptions.First(m =>
                                                                                          m.MessageHandlerType == typeof(AircraftLandedHandler)).SubscriptionFilter.MessageProperties);
        }
        public void MessageHandlerResolverReturnsMessageHandlerInstanceForCustomSubscriptionFilterMessageProperties()
        {
            var subscriptionFilter = new SubscriptionFilter
            {
                MessageProperties = new Dictionary <string, string>
                {
                    { "MessageType", "AL" }
                }
            };

            subscriptionFilter.Build(new(), typeof(AircraftLanded));

            var services = new ServiceCollection();
            var sut      = new MessageHandlerResolver(services);

            sut.SubcribeToMessage <AircraftLanded, AircraftLandedHandler>(subscriptionFilter);
            sut.Initialize();
            var handler = sut.Resolve("AL");

            Assert.NotNull(handler);
            Assert.IsType <AircraftLandedHandler>(handler);

            var messageContext = new MessageContext <AircraftLanded>(new BinaryData("Hello world!"), new object(),
                                                                     new Mock <IMessageBus>().Object);

            typeof(AircraftLandedHandler).GetMethod("HandleAsync").Invoke(handler, new object[] { messageContext });
        }
示例#4
0
        /// <summary>
        /// Creates a default subscription filter for a send port.
        /// </summary>
        /// <param name="targetApplication">The application in the target.</param>
        /// <param name="sendPort">The send port containing the filter to replicate.</param>
        /// <returns>A subscription filter.</returns>
        private SubscriptionFilter CreateDefaultSubscriptionFilter(Application targetApplication, SendPort sendPort)
        {
            _logger.LogDebug(TraceMessages.CreatingDefaultSendPortSubscription, RuleName, sendPort.Name);

            // Create filter expression
            string targetFilterExpression;

            if (sendPort.IsStatic)
            {
                targetFilterExpression = $"{ModelConstants.BizTalkSpTransportId} = '{targetApplication.Name.FormatKey()}.{sendPort.Name.FormatKey()}.{sendPort.PrimaryTransport.TransportType.Name}'";
            }
            else
            {
                // It's a dynamic port, so won't have a primary transport
                targetFilterExpression = $"{ModelConstants.BizTalkSpTransportId} = '{targetApplication.Name.FormatKey()}.{sendPort.Name.FormatKey()}'";
            }

            // Create a group, doesn't matter too much what the operation is as there is only one filter
            var targetFilterGroup = new OrFilterGroup();

            targetFilterGroup.Filters.Add(new Filter()
            {
                FilterExpression = targetFilterExpression
            });

            _logger.LogTrace(TraceMessages.CreatedSubscriptionFilterStatement, RuleName, targetFilterExpression);

            // Create filter and return
            var subscriptionFilter = new SubscriptionFilter(targetFilterGroup);

            _logger.LogTrace(TraceMessages.CreatedDefaultSubscriptionFilterGroupForSendPort, RuleName, targetFilterGroup.Operation, sendPort.Name);

            return(subscriptionFilter);
        }
示例#5
0
        public bool AddInterest <T>(T subscriber, string eventName, SubscriptionFilter filter) where T : ISpatialGrain // NOTE: rename?
        {
            // Check if a filter map exists for this event
            var result = _filters.TryGetValue(eventName, out var eventInterestFilters);

            if (!result) // If not, create the dictionary
            {
                eventInterestFilters = new Dictionary <ISpatialGrain, SubscriptionFilter>();
                _filters[eventName]  = eventInterestFilters;
            }
            // If the filter map exists, check if the grain already has a subscription
            else if (eventInterestFilters.ContainsKey(subscriber))
            {
                return(false);
            }
            // Create the subscription filter for this grain
            eventInterestFilters[subscriber] = filter;

            // Check if the interest map exists for this grain
            result = _interests.TryGetValue(subscriber, out var grainInterests);
            if (!result) // If not, create it
            {
                grainInterests         = new Dictionary <string, SubscriptionFilter>();
                _interests[subscriber] = grainInterests;
            }
            // Add the event to the grain
            grainInterests[eventName] = filter;
            return(true);
        }
示例#6
0
        public async Task <bool> HandleSubscription <T>(T subscriber, SubscriptionDetails details) where T : ISpatialGrain
        {
            var eventName = details.EventTypeFilter.GetTypename();
            var filter    = new SubscriptionFilter
            {
                Area             = details.Area,
                OriginTypeFilter = details.OriginTypeFilter
            };
            // Setup interest management
            var result = State.InterestManager.AddInterest(subscriber, eventName, filter);

            // If the subscription could not be added, return false
            if (!result)
            {
                return(false);
            }
            // Make sure events are forwarded
            var queue = State.InterestManager.GetForwardCommandsForSubscription(subscriber, eventName, filter);

            if (queue.Count > 0)
            {
                await ProcessForwardCommandQueue(queue);
            }
            await WriteStateAsync();

            return(true);
        }
示例#7
0
        public void AddsMessageVersionPropertyIfNoCustomMessageProperties()
        {
            var sut = new SubscriptionFilter();

            sut.Build(new MessageBusOptions(), typeof(Models.Events.V2.AircraftLanded));

            Assert.Equal(2, int.Parse(sut.MessageProperties[_defaultMessageVersionPropertyName]));
        }
示例#8
0
        private static List <MessageHandlerMapping> BuildMessageSubscriptions()
        {
            var subscriptionFilter = new SubscriptionFilter();

            subscriptionFilter.Build(new MessageBusOptions(), typeof(AircraftLandedHandler));

            return(new List <MessageHandlerMapping>
            {
                new MessageHandlerMapping(typeof(AircraftLandedHandler), typeof(AircraftTakenOffHandler), subscriptionFilter)
            });
        }
        protected static SubscriptionFilter BuildSubscriptionFilter <T>() where T : IMessage
        {
            var subscriptionFilter = new SubscriptionFilter
            {
                Label = typeof(T).Name
            };

            subscriptionFilter.Build(new MessageBusOptions(), typeof(T));

            return(subscriptionFilter);
        }
示例#10
0
        public void LabelReturnsLabelIfSet(Type typeOfMessage, string label)
        {
            var sut = new SubscriptionFilter
            {
                Label = label
            };

            sut.Build(new MessageBusOptions(), typeOfMessage);

            Assert.Equal(label, sut.Label);
            Assert.Equal(label, sut.EffectiveMessageLabel);
        }
        public void SubcribeToMessage <TMessage, TMessageHandler>(SubscriptionFilter subscriptionFilter)
            where TMessage : IMessage
            where TMessageHandler : IMessageHandler <TMessage>
        {
            ThrowIfNullSubscriptionFilter(subscriptionFilter);

            _services.AddTransient(typeof(IMessageHandler <>).MakeGenericType(typeof(TMessage)), typeof(TMessageHandler));

            _messageSubscriptions.Add(subscriptionFilter.EffectiveMessageLabel,
                                      new MessageHandlerMapping(typeof(TMessage), typeof(TMessageHandler), subscriptionFilter
                                                                ?? throw new ArgumentNullException(nameof(subscriptionFilter))));
        }
        public bool IsFilterMatch(object message, RoutingFilter messageFilter)
        {
            if (SubscriptionFilter == null)
            {
                if (messageFilter == null || messageFilter?.RoutingKey == "*")
                {
                    return(true);
                }
                return(false);
            }

            return(SubscriptionFilter?.EvaluateFilter(message, messageFilter) ?? true);
        }
示例#13
0
        public void ThrowsIfNoMessageTypeInCustomSubscriptionFilterProperties()
        {
            var sut = new SubscriptionFilter
            {
                MessageProperties = new Dictionary <string, string>
                {
                    { "SomethingElse", "AL" }
                }
            };

            sut.Build(new MessageBusOptions(), typeof(AircraftLanded));

            Assert.Throws <ArgumentNullException>(() => sut.EffectiveMessageLabel);
        }
示例#14
0
        public void CanCreateInstanceWithCustomSubscriptionFilter()
        {
            var subscriptionFilter = new SubscriptionFilter
            {
                MessageProperties = new Dictionary <string, string>()
            };
            var messageType        = typeof(AircraftLanded);
            var messageHandlerType = typeof(AircraftLandedHandler);
            var sut = new MessageHandlerMapping(messageType, messageHandlerType, subscriptionFilter);

            Assert.Equal(messageType.FullName, sut.MessageType.FullName);
            Assert.Equal(messageHandlerType.FullName, sut.MessageHandlerType.FullName);
            Assert.Equal(subscriptionFilter, sut.SubscriptionFilter);
        }
        protected static CorrelationRuleFilter BuildCorrelationRuleFilter(SubscriptionFilter subscriptionFilter)
        {
            var filter = new CorrelationRuleFilter
            {
                Subject = subscriptionFilter.Label
            };

            foreach (var property in subscriptionFilter.MessageProperties)
            {
                filter.ApplicationProperties.Add(property.Key, property.Value);
            }

            return(filter);
        }
示例#16
0
        public void SubscribesToMessagesWithoutCustomSubscriptionFilter()
        {
            SubscriptionFilter actualSubscriptionFilter = null;

            _mockMessageHandlerResolver.Setup(m => m.SubcribeToMessage <AircraftLanded, AircraftLandedHandler>(
                                                  It.IsAny <SubscriptionFilter>())).Callback <SubscriptionFilter>(s => actualSubscriptionFilter = s);

            _sut.SubscribeToMessage <AircraftLanded, AircraftLandedHandler>();

            var subscriptionFilter = new SubscriptionFilter();

            subscriptionFilter.Build(new MessageBusOptions(), typeof(AircraftLanded));
            Assert.Equal(nameof(AircraftLanded), actualSubscriptionFilter.Label);
            Assert.Equal(new Dictionary <string, string>(), actualSubscriptionFilter.MessageProperties);
        }
示例#17
0
        public void EffectiveMessageLabelReturnsMessageTypePropertyIfMessageTypePropertyIsSetAndLabelIsNotSet(Type typeOfMessage)
        {
            var sut = new SubscriptionFilter
            {
                MessageProperties = new Dictionary <string, string>
                {
                    { _defaultMessageTypePropertyName, typeOfMessage.Name }
                }
            };

            sut.Build(new MessageBusOptions(), typeOfMessage);

            Assert.Equal(typeOfMessage.Name, sut.MessageProperties[_defaultMessageTypePropertyName]);
            Assert.Null(sut.Label);
            Assert.False(sut.MessageProperties.ContainsKey(_defaultMessageVersionPropertyName));
            Assert.Equal(typeOfMessage.Name, sut.EffectiveMessageLabel);
        }
示例#18
0
        public void SubscribeToMessageUsesMessageTypeIfLabelNull(string messageType)
        {
            var subscriptionFilter = new SubscriptionFilter
            {
                MessageProperties = new Dictionary <string, string>
                {
                    { "MessageType", messageType }
                }
            };

            _sut.SubscribeToMessage <AircraftLanded, AircraftLandedHandler>(subscriptionFilter);

            _mockMessageHandlerResolver.Verify(m
                                               => m.SubcribeToMessage <AircraftLanded, AircraftLandedHandler>(It.Is <SubscriptionFilter>(s =>
                                                                                                                                         s.Label == null &&
                                                                                                                                         s.MessageProperties == subscriptionFilter.MessageProperties)),
                                               Times.Once);
        }
示例#19
0
        public void SubscribesToMessagesWithCustomProperties()
        {
            const string expectedMessageType = "AL";
            var          subscriptionFilter  = new SubscriptionFilter
            {
                MessageProperties = new Dictionary <string, string>
                {
                    { "MessageType", expectedMessageType }
                }
            };

            _sut.SubscribeToMessage <AircraftLanded, AircraftLandedHandler>(subscriptionFilter);

            _mockMessageHandlerResolver.Verify(m
                                               => m.SubcribeToMessage <AircraftLanded, AircraftLandedHandler>(It.Is <SubscriptionFilter>(s =>
                                                                                                                                         s.Label == null &&
                                                                                                                                         s.MessageProperties == subscriptionFilter.MessageProperties)),
                                               Times.Once);
        }
        public static void PublishWorkflow(this WorkflowManagementClient client, string workflowName, string xamlFilePath, Collection<ExternalVariable> externalVariables, IDictionary<string, string> configValues, SubscriptionFilter activationFilter = null)
        {
            // publish the activity description related with the workflow
            client.Activities.Publish(
                new ActivityDescription(WorkflowUtils.Translate(xamlFilePath)) { Name = workflowName },true,true);

            // now, publish the workflow description
            WorkflowDescription description = new WorkflowDescription
            {
                Name = workflowName,
                ActivityPath = workflowName,
            };

            // add external variables
            if (externalVariables != null)
            {
                externalVariables
                    .ToList()
                    .ForEach(ev => description.ExternalVariables.Add(ev));
            }

            // add config
            if (configValues != null)
            {
                description.Configuration = new WorkflowConfiguration();
                configValues
                    .ToList()
                    .ForEach(c => description.Configuration.AppSettings.Add(c));
            }

            // add activation filter
            if (activationFilter != null)
            {
                description.ActivationDescription = new SubscriptionActivationDescription
                {
                    Filter = activationFilter
                };
            }

            // publish!
            client.Workflows.Publish(description);
        }
示例#21
0
        public async void TestForwardCommandQueueDelta()
        {
            var im = new InterestManager();

            im.Initialize(2d, new Tuple <int, int>(2, 2));
            var filter = new SubscriptionFilter
            {
                Area = Circle.WithRadius(2d)
            };
            var subscriber = new SpatialGrainStub();

            im.AddPosition(subscriber, new Vector3d(5d, 5d, 0d));
            var queue1 = im.GetForwardCommandsForSubscription(subscriber, "TEST", filter);

            Assert.Equal(queue1.Count, 8);
            // All forwards for event TEST exist so same subscription should result in no commands
            var queue2 = im.GetForwardCommandsForSubscription(subscriber, "TEST", filter);

            Assert.Equal(queue2.Count, 0);
        }
        public async Task ReceivesAndSendsEventMessagePropertyFilter()
        {
            var inputSubscription = nameof(ReceivesAndSendsEventMessagePropertyFilter);

            await CreateEndToEndTestSubscriptionsAsync(inputSubscription);

            var subscriptionFilter = new SubscriptionFilter
            {
                MessageProperties = new Dictionary <string, string> {
                    { "MessageType", "ALR" }
                }
            };

            var services = new ServiceCollection();

            services.AddHostedService <MessageBusHostedService>()
            .AddSingleton <IMessageTracker, MessageTracker>()
            .AddMessageBus(new AzureServiceBusClientBuilder(Configuration["Hostname"],
                                                            Configuration["Topic"], inputSubscription, Configuration["TenantId"]))
            .SubscribeToMessage <AircraftLeftRunway, AircraftLeftRunwayHandler>(subscriptionFilter);
            _serviceProvider = services.BuildServiceProvider();
            await StartMessageBusHostedServiceAsync(_serviceProvider);

            var aircraftLeftRunwayEvent = new AircraftLeftRunway {
                RunwayId = Guid.NewGuid().ToString()
            };

            await SendMessagesAsync(aircraftLeftRunwayEvent, null, 1, "ALR");

            await Task.Delay(TimeSpan.FromSeconds(4));

            Assert.DoesNotContain(await ReceiveMessagesForSubscriptionAsync(inputSubscription),
                                  m => m.Body.ToObjectFromJson <AircraftTakenOff>().AircraftId == aircraftLeftRunwayEvent.RunwayId);
            Assert.Single(await ReceiveMessagesForSubscriptionAsync($"{inputSubscription}-Output"),
                          m => m.Subject == nameof(AircraftReachedGate) &&
                          m.Body.ToObjectFromJson <AircraftReachedGate>().AirlineId == aircraftLeftRunwayEvent.RunwayId);
        }
示例#23
0
 public static void PublishWorkflowString(this WorkflowManagementClient client, string workflowName, string xamlFilePath, SubscriptionFilter activationFilter = null)
 {
     PublishWorkflowString(client, workflowName, xamlFilePath, null, null, activationFilter);
 }
 public static SubscriptionListRequestBuilder List(SubscriptionFilter filter)
 {
     return(new SubscriptionListRequestBuilder(filter));
 }
 public SubscriptionListRequestBuilder(SubscriptionFilter filter)
     : this()
 {
     this.Filter = filter;
 }
 public static void PublishWorkflowString(this WorkflowManagementClient client, string workflowName, string xamlFilePath, SubscriptionFilter activationFilter = null)
 {
     PublishWorkflowString(client, workflowName, xamlFilePath, null, null, activationFilter);
 }
 public static void PublishWorkflow(this WorkflowManagementClient client, string workflowName, string XamlFile, SubscriptionFilter activationFilter = null)
 {
     PublishWorkflow(client, workflowName, XamlFile, null, null, activationFilter);
 }
        public CrayonApiClientResult <ApiCollection <Subscription> > Get(string token, SubscriptionFilter filter = null)
        {
            var uri = "/api/v1/subscriptions/".Append(filter);

            return(_client.Get <ApiCollection <Subscription> >(token, uri));
        }
 public static void PublishWorkflow(this WorkflowManagementClient client, string workflowName, string xamlFilePath, Collection<ExternalVariable> externalVariables, SubscriptionFilter activationFilter = null)
 {
     PublishWorkflow(client, workflowName, xamlFilePath, externalVariables, null, activationFilter);
 }
 public static void PublishWorkflow(this WorkflowManagementClient client, string workflowName, string xamlFilePath, IDictionary<string, string> configValues, SubscriptionFilter activationFilter = null)
 {
     PublishWorkflow(client, workflowName, xamlFilePath, null, configValues, activationFilter);
 }
示例#31
0
        /// <summary>
        /// Creates a default subscription filter for a send port.
        /// </summary>
        /// <param name="targetApplication">The application in the target.</param>
        /// <param name="sendPort">The send port containing the filter to replicate.</param>
        /// <returns>A subscription filter.</returns>
        private SubscriptionFilter CreateSubscriptionFilter(Application targetApplication, SendPort sendPort)
        {
            _logger.LogDebug(TraceMessages.CreatingSendPortSubscription, RuleName, sendPort.Name);

            // Create an overall OR filter group so that if any sub-group matches a condition
            var targetFilterGroup = new OrFilterGroup();

            // Add default
            string defaultTargetFilterExpression;

            if (sendPort.IsStatic)
            {
                defaultTargetFilterExpression = $"{ModelConstants.BizTalkSpTransportId} = '{targetApplication.Name.FormatKey()}.{sendPort.Name.FormatKey()}.{sendPort.PrimaryTransport.TransportType.Name}'";
            }
            else
            {
                // It's a dynamic port, so won't have a primary transport
                defaultTargetFilterExpression = $"{ModelConstants.BizTalkSpTransportId} = '{targetApplication.Name.FormatKey()}.{sendPort.Name.FormatKey()}'";
            }

            targetFilterGroup.Groups.Add(new AndFilterGroup()
            {
                Filters = { new Filter()
                            {
                                FilterExpression = defaultTargetFilterExpression
                            } }
            });

            // Loop around the filter groups, converting each one to an AND filter group with a list of filter expressions
            foreach (var sendPortFilterGroup in sendPort.FilterExpression.Group)
            {
                var targetFilterSubGroup = new AndFilterGroup();
                foreach (var statement in sendPortFilterGroup.Statement)
                {
                    Filter filter             = null;
                    var    expressionProperty = MapSubscriptionFilterProperty(statement.Property);

                    switch (statement.Operator)
                    {
                    // Equals
                    case 0:

                        filter = new Filter()
                        {
                            FilterExpression = $"{expressionProperty} = '{statement.Value}'"
                        };
                        break;

                    // LessThan
                    case 1:

                        filter = new Filter()
                        {
                            FilterExpression = $"{expressionProperty} < '{statement.Value}'"
                        };
                        break;

                    // LessThanEqualTo
                    case 2:

                        filter = new Filter()
                        {
                            FilterExpression = $"{expressionProperty} <= '{statement.Value}'"
                        };
                        break;

                    // GreaterThan
                    case 3:

                        filter = new Filter()
                        {
                            FilterExpression = $"{expressionProperty} > '{statement.Value}'"
                        };
                        break;

                    // GreaterThanEqualTo
                    case 4:

                        filter = new Filter()
                        {
                            FilterExpression = $"{expressionProperty} >= '{statement.Value}'"
                        };
                        break;

                    // NotEqual
                    case 5:

                        filter = new Filter()
                        {
                            FilterExpression = $"{expressionProperty} != '{statement.Value}'"
                        };
                        break;

                    // Exists
                    case 6:

                        filter = new Filter()
                        {
                            FilterExpression = $"EXISTS ( {expressionProperty} )"
                        };
                        break;

                    default:

                        _logger.LogError(ErrorMessages.SubscriptionFilterOperatorNotSupported, statement.Operator);
                        Context.Errors.Add(new ErrorMessage(string.Format(CultureInfo.CurrentCulture, ErrorMessages.SubscriptionFilterOperatorNotSupported, statement.Operator)));

                        continue;
                    }

                    targetFilterSubGroup.Filters.Add(filter);

                    _logger.LogTrace(TraceMessages.CreatedSubscriptionFilterStatement, RuleName, filter.FilterExpression);
                }

                _logger.LogTrace(TraceMessages.CreatedSubscriptionFilterSubGroup, RuleName, targetFilterSubGroup.Operation, targetFilterSubGroup.Filters.Count);

                // Add to filter group
                targetFilterGroup.Groups.Add(targetFilterSubGroup);
            }

            _logger.LogTrace(TraceMessages.CreatedSubscriptionFilterGroupForSendPort, RuleName, targetFilterGroup.Operation, sendPort.Name);

            // Create filter and return
            var subscriptionFilter = new SubscriptionFilter(targetFilterGroup);

            return(subscriptionFilter);
        }
示例#32
0
 public static void PublishWorkflow(this WorkflowManagementClient client, string workflowName, string XamlFile, SubscriptionFilter activationFilter = null)
 {
     PublishWorkflow(client, workflowName, XamlFile, null, null, activationFilter);
 }
示例#33
0
 public static void PublishWorkflow(this WorkflowManagementClient client, string workflowName, string xamlFilePath, Collection <ExternalVariable> externalVariables, SubscriptionFilter activationFilter = null)
 {
     PublishWorkflow(client, workflowName, xamlFilePath, externalVariables, null, activationFilter);
 }
示例#34
0
 public static void PublishWorkflow(this WorkflowManagementClient client, string workflowName, string xamlFilePath, IDictionary <string, string> configValues, SubscriptionFilter activationFilter = null)
 {
     PublishWorkflow(client, workflowName, xamlFilePath, null, configValues, activationFilter);
 }
示例#35
0
        public static void PublishWorkflowString(this WorkflowManagementClient client, string workflowName, string xamlFile, Collection <ExternalVariable> externalVariables, IDictionary <string, string> configValues, SubscriptionFilter activationFilter = null)
        {
            // publish the activity description related with the workflow
            client.Activities.Publish(
                new ActivityDescription(WorkflowUtils.TranslateString(xamlFile))
            {
                Name = workflowName
            }, true, true);

            // now, publish the workflow description
            WorkflowDescription description = new WorkflowDescription
            {
                Name         = workflowName,
                ActivityPath = workflowName,
            };

            // add external variables
            if (externalVariables != null)
            {
                externalVariables
                .ToList()
                .ForEach(ev => description.ExternalVariables.Add(ev));
            }

            // add config
            if (configValues != null)
            {
                description.Configuration = new WorkflowConfiguration();
                configValues
                .ToList()
                .ForEach(c => description.Configuration.AppSettings.Add(c));
            }

            // add activation filter
            if (activationFilter != null)
            {
                description.ActivationDescription = new SubscriptionActivationDescription
                {
                    Filter = activationFilter
                };
            }

            // publish!
            client.Workflows.Publish(description);
        }