Skip to main content

policy-compilation

Conventions and patterns for creating policy compilers in the Azure API Management policy toolkit. Use this skill when creating or modifying compiler classes in src/Core/Compiling/Policy/.

معلومات المصدر

المستودع
Azure/azure-api-management-policy-toolkit
آخر نشاط في المصدر
٨ مارس ٢٠٢٦ في ١٨:٥٣
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
٩٥
التفرعات
٣٧

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
name
policy-compilation
description
Conventions and patterns for creating policy compilers in the Azure API Management policy toolkit. Use this skill when creating or modifying compiler classes in src/Core/Compiling/Policy/.
# Policy Compilation Patterns This skill describes how to implement compilers that convert authoring models to XML in the Azure API Management policy toolkit. ## Compiler Class — `src/Core/Compiling/Policy/{PolicyName}Compiler.cs` ### Config-Based Compiler Template (Most Common) Use this for policies that take a config object parameter. ```csharp // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. using System.Xml.Linq; using Microsoft.Azure.ApiManagement.PolicyToolkit.Authoring; using Microsoft.Azure.ApiManagement.PolicyToolkit.Compiling.Diagnostics; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; namespace Microsoft.Azure.ApiManagement.PolicyToolkit.Compiling.Policy; public class {PolicyName}Compiler : IMethodPolicyHandler { public string MethodName => nameof(I{Section}Context.{MethodName}); public void Handle(IDocumentCompilationContext context, InvocationExpressionSyntax node) { if (!node.TryExtractingConfigParameter<{PolicyName}Config>(context, "{xml-element-name}", out var values)) { return; } var element = new XElement("{xml-element-name}"); // Required attributes — report diagnostic and return on failure if (!element.AddAttribute(values, nameof({PolicyName}Config.{RequiredProp}), "{xml-attr-name}")) { context.Report(Diagnostic.Create( CompilationErrors.RequiredParameterNotDefined, node.GetLocation(), "{xml-element-name}", nameof({PolicyName}Config.{RequiredProp}) )); return; } // Optional attributes — no error reporting needed element.AddAttribute(values, nameof({PolicyName}Config.{OptionalProp}), "{xml-attr-name}"); // Child elements — iterate sub-configs if applicable // (see "Handling Child Elements" below) context.AddPolicy(element); } } ``` ### Direct-Parameter Compiler Template Use this for policies with 1–2 simple parameters and no optional fields (e.g., `SetMethod`, `FindAndReplace`). ```csharp public class {PolicyName}Compiler : IMethodPolicyHandler { public string MethodName => nameof(I{Section}Context.{MethodName}); public void Handle(IDocumentCompilationContext context, InvocationExpressionSyntax node) { if (node.ArgumentList.Arguments.Count != {expectedCount}) { context.Report(Diagnostic.Create( CompilationErrors.ArgumentCountMissMatchForPolicy, node.ArgumentList.GetLocation(), "{xml-element-name}")); return; } var value = node.ArgumentList.Arguments[0].Expression.ProcessParameter(context); context.AddPolicy(new XElement("{xml-element-name}", value)); } } ``` ## Auto-Registration Compiler classes do **not** need manual DI registration. The `CompilerModule.AddMethodPolicyHandlers()` method in `src/Core/IoC/CompilerModule.cs` uses reflection to find all types matching: - `IsClass: true` - `IsAbstract: false` - `IsPublic: true` - `Namespace: "Microsoft.Azure.ApiManagement.PolicyToolkit.Compiling.Policy"` - Implements `IMethodPolicyHandler` Just ensure your compiler class meets all these criteria and it will be auto-registered. ## Key Utility Methods All utility methods live in `src/Core/Compiling/CompilerUtils.cs` and `src/Core/Compiling/SyntaxExtensions.cs`. You do not need to modify these files — just use their APIs. ### `TryExtractingConfigParameter<T>` Extracts the config object from the method invocation. Returns a dictionary of property name → `InitializerValue`. Returns `false` and reports diagnostics if extraction fails. ### `AddAttribute` Extension method on `XElement`. Adds an XML attribute from the values dictionary: - **Property name to XML attribute conversion**: C# property names are converted to kebab-case XML attribute names automatically. For example: - `RenewalPeriod` → `renewal-period` - `RetryAfterHeaderName` → `retry-after-header-name` - The conversion happens in the `AddAttribute` helper; you supply the kebab-case name in the compiler call. - **Expression handling**: Automatically wraps expression values in `@(...)` when the value comes from an expression method. - **Return value**: `true` if the attribute was added, `false` if the key was not present (property not set). ### `GenericCompiler.HandleList` Utility in `src/Core/Compiling/Policy/GenericCompiler.cs` for compiling string arrays into repeated child elements: ```csharp GenericCompiler.HandleList(element, values, nameof(Config.Claims), "required-claims", "claim"); // Produces: <required-claims><claim>value1</claim><claim>value2</claim></required-claims> ``` Used by `ValidateJwtCompiler` and `ValidateAzureAdTokenCompiler`. ### `ProcessParameter` Extension method on `ExpressionSyntax`. Processes a raw argument into its string value, handling both constants and expressions. Used in direct-parameter compilers. ## Handling Child Elements ### Typed Sub-Config Arrays For child elements backed by sub-config records (e.g., `ApiRateLimit[]`): ```csharp if (values.TryGetValue(nameof({PolicyName}Config.{ChildArray}), out var items)) { foreach (var item in items.UnnamedValues!) { var childElement = new XElement("{child-element-name}"); var childValues = item.NamedValues!; childElement.AddAttribute(childValues, nameof({SubConfig}.{Prop}), "{attr-name}"); // ... more attributes element.Add(childElement); } } ``` ### String Arrays For simple string arrays (e.g., IP addresses): ```csharp if (values.TryGetValue(nameof({PolicyName}Config.{StringArray}), out var items)) { foreach (var item in items.UnnamedValues!) { element.Add(new XElement("{child-element-name}", item.Value!)); } } ``` ## Diagnostics Error reporting uses descriptors from `src/Core/Compiling/Diagnostics/CompilationErrors.cs`. Common ones: | Descriptor | When to Use | |---|---| | `RequiredParameterNotDefined` | A required attribute/property is missing | | `RequiredParameterIsEmpty` | A required array is present but empty | | `AtLeastOneOfTwoShouldBeDefined` | At least one of two mutually supportive properties must be set | | `OnlyOneOfTwoShouldBeDefined` | Exactly one of two mutually exclusive properties must be set | | `PolicyArgumentIsNotOfRequiredType` | A child element has the wrong type | | `ArgumentCountMissMatchForPolicy` | Wrong number of arguments in direct-parameter compilers | ## XML Namespaces - By default, compiled XML policies **do not** include `xmlns` attributes. XML elements use the element name directly (e.g., `<rate-limit />`), and the namespace context is managed at the gateway level. - If a specific policy requires namespace prefixes or explicit schema references, this must be specified during authoring Phase 1. Handle with care and test thoroughly. ## `IReturnValueMethodPolicyHandler` A second compiler interface exists for policies that return a value assigned to a variable (e.g., `AuthenticationManagedIdentity` returning a token). This interface is **not** auto-registered by `CompilerModule` and the syntax compiler for it (`LocalDeclarationStatementCompiler`) is currently commented out in `CompilerModule.cs`. If you encounter a policy that assigns its result to a variable, flag this to the user as a special case requiring manual wiring.
عرض على GitHub