$npx -y skills add managedcode/dotnet-skills --skill managedcode-orleans-graphIntegrate ManagedCode.Orleans.Graph into an Orleans-based .NET application for grain-call policy enforcement, deadlock detection, live-call telemetry, and Mermaid graph diagnostics. USE FOR: ManagedCode.Orleans.Graph integration; allowed grain transitions; Orleans call filters; l
| 1 | # ManagedCode.Orleans.Graph |
| 2 | |
| 3 | ## Trigger On |
| 4 | |
| 5 | - integrating `ManagedCode.Orleans.Graph` into an Orleans-based system |
| 6 | - enforcing which grain interfaces may call other grain interfaces and methods |
| 7 | - detecting unsafe runtime grain call cycles or intentional self-reentrancy |
| 8 | - generating configured-policy or live-call Mermaid diagrams |
| 9 | - running observe mode to discover real traffic before locking down a policy |
| 10 | |
| 11 | ## Install |
| 12 | |
| 13 | Current upstream release reviewed: `v10.0.3`. |
| 14 | |
| 15 | ```bash |
| 16 | dotnet add package ManagedCode.Orleans.Graph |
| 17 | ``` |
| 18 | |
| 19 | The upstream package targets the current .NET 10 / Orleans 10 stack. Do not add it to older Orleans applications without first checking target frameworks and Orleans package compatibility. |
| 20 | |
| 21 | ## Workflow |
| 22 | |
| 23 | 1. Confirm the application needs grain-call policy enforcement or live-call diagnostics. If the task is generic graph data traversal, use normal Orleans grain modeling instead. |
| 24 | 2. Register Orleans.Graph filters in the silo with `AddOrleansGraph(...)`. |
| 25 | 3. Model the policy from source grain to target grain and method. Start with explicit allow rules for client entry points and grain-to-grain transitions. |
| 26 | 4. Use `AllowAll()` observe mode only to discover traffic before enforcement. Keep a follow-up step to convert observed edges into reviewed policy. |
| 27 | 5. Register the client-side outgoing filter with `clientBuilder.AddOrleansGraph()` only when Orleans clients should participate in call-history tracking. |
| 28 | 6. Use attributes when colocating policy with grain contracts is clearer than central fluent setup. |
| 29 | 7. Generate Mermaid diagrams and inspect policy edges for review artifacts. |
| 30 | 8. Validate with real Orleans runtime tests, including timer, reminder, hosted-service, and stateless-worker call origins when those are part of the topology. |
| 31 | |
| 32 | ```mermaid |
| 33 | flowchart LR |
| 34 | A["Orleans call"] --> B["Outgoing filter records source"] |
| 35 | B --> C["Incoming filter checks transition policy"] |
| 36 | C --> D{"Allowed?"} |
| 37 | D -->|Yes| E["Target grain method runs"] |
| 38 | D -->|No| F["Blocked before target code"] |
| 39 | E --> G["Telemetry worker aggregates live edge"] |
| 40 | G --> H["Telemetry grain / Mermaid graph"] |
| 41 | ``` |
| 42 | |
| 43 | ## Practical Usage |
| 44 | |
| 45 | ### Enforce a grain transition |
| 46 | |
| 47 | ```csharp |
| 48 | using ManagedCode.Orleans.Graph.Extensions; |
| 49 | |
| 50 | siloBuilder.AddOrleansGraph(graph => |
| 51 | { |
| 52 | graph.AllowClientCallGrain<IOrderGrain>(); |
| 53 | |
| 54 | graph.AddGrainTransition<IOrderGrain, IPaymentGrain>() |
| 55 | .Method( |
| 56 | source => source.SubmitAsync(GraphParam.Any<Order>()), |
| 57 | target => target.ChargeAsync(GraphParam.Any<Payment>())) |
| 58 | .And(); |
| 59 | |
| 60 | graph.AddGrain<IPaymentGrain>() |
| 61 | .WithReentrancy(); |
| 62 | }); |
| 63 | ``` |
| 64 | |
| 65 | ### Discover traffic before enforcement |
| 66 | |
| 67 | ```csharp |
| 68 | siloBuilder.AddOrleansGraph( |
| 69 | configureFilters: filters => |
| 70 | { |
| 71 | filters.LiveGraphFlushPeriod = TimeSpan.FromSeconds(1); |
| 72 | }, |
| 73 | configureGraph: graph => |
| 74 | { |
| 75 | graph.AllowAll(); |
| 76 | }); |
| 77 | |
| 78 | clientBuilder.AddOrleansGraph(); |
| 79 | ``` |
| 80 | |
| 81 | After the app receives traffic, inspect the observed graph: |
| 82 | |
| 83 | ```csharp |
| 84 | var telemetry = grainFactory.GetGrain<IOrleansGraphTelemetryGrain>( |
| 85 | Constants.LiveGraphTelemetryGrainKey); |
| 86 | |
| 87 | var observedGraph = await telemetry.GetObservedGraphAsync(); |
| 88 | var mermaid = await telemetry.GenerateLiveMermaidDiagramAsync(); |
| 89 | ``` |
| 90 | |
| 91 | ### Use attributes on grain contracts |
| 92 | |
| 93 | ```csharp |
| 94 | using ManagedCode.Orleans.Graph.Attributes; |
| 95 | |
| 96 | [AllowClientCall] |
| 97 | [AllowGrainCall( |
| 98 | typeof(IPaymentGrain), |
| 99 | AllowAllMethods = false, |
| 100 | SourceMethods = [nameof(IOrderGrain.SubmitAsync)], |
| 101 | TargetMethods = [nameof(IPaymentGrain.ChargeAsync)])] |
| 102 | public interface IOrderGrain : IGrainWithStringKey |
| 103 | { |
| 104 | Task SubmitAsync(Order order); |
| 105 | } |
| 106 | |
| 107 | [AllowSelfReentrancy] |
| 108 | public interface IPaymentGrain : IGrainWithStringKey |
| 109 | { |
| 110 | Task ChargeAsync(Payment payment); |
| 111 | } |
| 112 | ``` |
| 113 | |
| 114 | ## Options And Constraints |
| 115 | |
| 116 | - `AllowAll()` is an observe/discovery mode, not a finished production policy. |
| 117 | - `AllowClientCallGrain<T>()` is required for client-originated entry points that should be allowed. |
| 118 | - `TrackOrleansGraphInternalCalls` should stay off unless debugging Orleans.Graph itself. |
| 119 | - `RegisterGrainTimer` callbacks use `*` as the source method because Orleans does not expose a grain interface method for that callback. |
| 120 | - Reminder callbacks use the source grain identity a |