0

I'm trying to construct an Azure ServiceBus Subscription Rule that will have either a correlation filter or sql filter depending on the length of param's subjectFilter array property. I tried this using if with union, based on this answer. However, it looks like the object is constructed with all properties. For example, the sql filter errors with "At least one system or user property must be set for a correlation filter."

Here's my code (simplified).

  • The copy variable contains properties to use for each subscription name and filterProperties, with defines a filterType and is used as the base properties object.
  • It also declares a separate object for the sqlFilterProperties and correlationFilterProperties, respectively.
  • Either the sqlFilterProperties or correlationFilterProperties object should be unioned with the filterProperties to construct the complete properties.
{
    "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "resourceName": {
            "type": "string"
        },
        "topics": {
            "type": "array"
        },
        "subscriptionName": {
            "type": "string"
        }
    },
    "variables": {
        "apiVersion": "2018-01-01-preview",
        "copy": [
            {
                "name": "subscriptions",
                "count": "[length(parameters('topics'))]",
                "input": {
                    "name": "[concat(parameters('resourceName'), '/', parameters('topics')[copyIndex('subscriptions')].name, '/', parameters('subscriptionName'))]",
                    "filterProperties": {
                        "filterType": "[if(greater(length(parameters('topics')[copyIndex('subscriptions')].subjectFilter),1),'sqlFilter','correlationFilter')]"
                    },
                    "sqlFilterProperties": {
                        "sqlFilter": {
                            "sqlExpression": "[concat('sys.subject in (''',join(parameters('topics')[copyIndex('subscriptions')].subjectFilter,''','''), ''')')]",
                            "requiresPreprocessing": false
                        }
                    },
                    "correlationFilterProperties": {
                        "correlationFilter": {
                            "subject": "[parameters('topics')[copyIndex('subscriptions')].subjectFilter[0]]",
                            "requiresPreprocessing": false
                        }
                    }
                }
            }
        ]
    },
    "resources": [
        {
            "type": "Microsoft.ServiceBus/namespaces/topics/subscriptions/rules",
            "apiVersion": "[variables('apiVersion')]",
            "copy": {
                "name": "subscriptionFilters",
                "count": "[length(parameters('topics'))]"
            },
            "name": "[concat(variables('subscriptions')[copyIndex()].name, '/subject')]",
            "properties": "[union(variables('subscriptions')[copyIndex()].filterProperties, if(startsWith(variables('subscriptions')[copyIndex()].filterProperties.filterType, 'sql'), variables('subscriptions')[copyIndex()].sqlFilterProperties, variables('subscriptions')[copyIndex()].correlationFilterProperties) )]"
        }
    ]
}
Rachel
  • 686
  • 1
  • 6
  • 18

2 Answers2

0

Rather than using the union method directly, you can conditionally assign the filter properties based on the filter type. Compare the filter type with 'correlationFilter' or 'sqlFilter' using the equals function.

You can make the changes listed below to your code and try deployment once again.

"correlationFilter":  "[if(equals(variables('subscriptions')[copyIndex()].filterProperties.filterType, 'correlationFilter'), variables('subscriptions')[copyIndex()].correlationFilterProperties.correlationFilter)]",  
"sqlFilter":  "[if(equals(variables('subscriptions')[copyIndex()].filterProperties.filterType, 'sqlFilter'), variables('subscriptions')[copyIndex()].sqlFilterProperties.sqlFilter)]"

Alternatively, you can also use system properties like (ContentType, Label, MessageId, ReplyTo) and user-defined values to filter, when you use the CorrelationRuleFilter default constructor. Use the IDictionary string, object> property Properties to supply user-defined properties for the correlation filter as detailed here.

Jahnavi
  • 3,076
  • 1
  • 3
  • 10
  • That syntax doesn't work, I get `Unable to evaluate template language function 'if': function requires 3 argument(s) while 2 were provided`. When I pass `json('null')` as the third arg, I get the same errors as when I use `union` in my code. – Rachel Jul 03 '23 at 15:19
  • Can you refer this [doc](https://github.com/MicrosoftDocs/azure-docs/blob/main/articles/azure-resource-manager/troubleshooting/error-invalid-template.md)? – Jahnavi Jul 04 '23 at 09:00
  • As mentioned, I resolved the error by passing `json(null)` as the third arg and get the same errors as when I use `union` in my code. IOW putting aside the syntax problem, `if` has same behavior as `union`. – Rachel Jul 04 '23 at 16:58
0

I got this answer from Microsoft through a support ticket. The problem is subject metadata property is actually called label when creating filters. (In C# it is called Subject.) So simply changing the sqlExpression to use sys.Label and the correlationFilter properties to use Label solved the problem.

See docs

https://learn.microsoft.com/en-us/azure/service-bus-messaging/service-bus-messages-payloads

https://learn.microsoft.com/en-us/dotnet/api/microsoft.azure.servicebus.message.label?view=azure-dotnet

Rachel
  • 686
  • 1
  • 6
  • 18