Reflection

Register the reflection tool suite to list registered roots, inspect live object state, describe runtime types, and allow tightly scoped writes or method invocations.

Warning: This suite includes Critical tools and can inspect live runtime state, mutate allow-listed members, or invoke allow-listed methods. Keep root registration, traversal boundaries, and write permissions narrowly scoped to local development workflows. You must not ever distribute these tools in a release build.

Install

dotnet add package Ansight.Tools.Reflection

Register the Suite

using Ansight;
using Ansight.Tools.Reflection;

var session = new DebugSessionViewModel();

var options = Options.CreateBuilder()
    .WithReflectionTools(reflection =>
    {
        reflection.WithDefaultMemberVisibility(ReflectionMemberVisibility.PublicOnly);
        reflection.WithAssemblyTraversalMode(ReflectionAssemblyTraversalMode.AllowListedOnly);
        reflection.WithNamespaceTraversalMode(ReflectionNamespaceTraversalMode.AllowListedOnly);
        reflection.AllowNamespacePrefix("MyApp.ViewModels");
        reflection.AddRoot(
            "session",
            session,
            new ReflectionRootMetadata("Current Session")
            {
                Description = "Active session view model",
                Category = "view-model",
                Tags = ["debug", "session"],
                ContainsSensitiveData = true,
                Attributes = new Dictionary<string, string>
                {
                    ["team"] = "sdk"
                }
            },
            root => root
                .AllowWritableMembers("SelectedTab")
                .AllowAllWritableMembersOn<DebugSessionViewModel>()
                .AllowInvokableMethods("Refresh()", "Child#Rename(System.String)")
                .AllowAllInvokableMethodsOn<DebugSessionViewModel>());
    })
    .WithReadWriteToolAccess()
    .Build();

Registration API

  • AddRoot(string id, object target, ReflectionRootMetadata metadata, ...): registers a direct weak reference. This is the default for direct object registration.
  • AddStrongRoot(...): registers a direct strong reference when the tool suite should retain the object.
  • AddRoot(string id, Func<object?> resolver, ReflectionRootMetadata metadata, ...): resolves the object on demand for each tool call.
  • WithAssemblyTraversalMode(...): choose AllowListedOnly or AllowAll for assembly-based traversal boundaries.
  • WithNamespaceTraversalMode(...): choose AllowListedOnly or AllowAll for namespace-based traversal boundaries.
  • AllowAssembly(...) / AllowAssemblies(...): add assembly allow-list entries when assembly traversal stays in AllowListedOnly.
  • AllowNamespacePrefix(...) / AllowNamespacePrefixes(...): add namespace-prefix allow-list entries when namespace traversal stays in AllowListedOnly.
  • WithDefaultMemberVisibility(...): set the global visibility rule. The default is PublicOnly.
  • WithMemberVisibility(...): override member visibility for one root.
  • AllowWritableMembers(...): allow field or property writes by relative path such as SelectedTab or Child.Name.
  • AllowAllWritableMembersOn<T>() / AllowAllWritableMembersOn(params Type[] types): allow writes for all writable fields and properties on reachable objects assignable to those types.
  • AllowAllWritableMembers(): allow writes for all writable fields and properties reachable from the root.
  • AllowInvokableMethods(...): allow instance method calls using Method(Type) for root targets or Path#Method(Type) for nested targets.
  • AllowAllInvokableMethodsOn<T>() / AllowAllInvokableMethodsOn(params Type[] types): allow all instance methods on reachable objects assignable to those types.
  • AllowAllInvokableMethods(): allow all instance methods reachable from the root.

Root Metadata

ReflectionRootMetadata requires DisplayName and also supports:

  • Description
  • Category
  • Tags
  • ContainsSensitiveData
  • Attributes

Specific Concerns

  • The suite never reflects arbitrary process objects. Apps must register every root explicitly.
  • Direct object roots use weak references by default. Use AddStrongRoot(...) only when the root must stay alive for the lifetime of the suite.
  • Expansion is stateless. Every call resolves from the root again rather than using persistent object handles.
  • Recursive traversal is allow-listed by default. If you do not configure allow-list entries or explicitly switch a traversal mode to AllowAll, child object snapshots stay opaque.
  • Types outside the configured assembly or namespace boundary return opaque previews instead of recursive members.
  • Non-public members stay hidden unless you opt into ReflectionMemberVisibility.PublicAndNonPublic.
  • Reads are controlled by root registration, traversal boundaries, and member visibility. You do not need a separate read allow-list.
  • reflect.set_member_value and reflect.invoke_method are Write tools. They require explicit per-root path, type, or wildcard enablement even when the runtime guard allows writes.
  • Collection-element writes and static method invocation are out of scope in v1.

If you want unrestricted traversal within registered roots, opt in explicitly:

reflection.WithAssemblyTraversalMode(ReflectionAssemblyTraversalMode.AllowAll);
reflection.WithNamespaceTraversalMode(ReflectionNamespaceTraversalMode.AllowAll);

Path Syntax

  • Property.SubProperty
  • [index]
  • ["key"]

Tool Matrix

NameIdScopeDescriptionSecurity
List Reflection Rootsreflect.list_rootsReadLists the registered live object roots and their capabilities.High
Inspect Objectreflect.inspect_objectReadReturns a stateless snapshot of a registered live object or nested path.Critical
Describe Typereflect.describe_typeReadReturns runtime type metadata without reading live object values.Moderate
Set Member Valuereflect.set_member_valueWriteWrites an explicitly allow-listed field or property.Critical
Invoke Methodreflect.invoke_methodWriteInvokes an explicitly allow-listed instance method.Critical

List Reflection Roots

Arguments:

  • none

Returns:

  • roots
  • count
  • capturedAtUtc

Each root descriptor includes:

  • id
  • metadata
  • registrationKind
  • referenceStrength
  • available
  • runtimeType
  • memberVisibility
  • canWriteMembers
  • canInvokeMethods
  • resolutionError

Example:

{
  "toolId": "reflect.list_roots",
  "arguments": {}
}

Inspect Object

Arguments:

  • root: required registered root id
  • path: optional nested member or collection path
  • maxDepth: recursive expansion depth, default 1, maximum 4
  • maxItemsPerCollection: collection item limit, default 10, maximum 64

Returns:

  • root
  • path
  • snapshot
  • capturedAtUtc

Snapshot payloads include common fields such as:

  • declaredType
  • runtimeType
  • kind
  • isNull
  • preview
  • expandable

Expanded snapshots may also include:

  • members
  • methods
  • items
  • truncated
  • opaque
  • cycleDetected

Example:

{
  "toolId": "reflect.inspect_object",
  "arguments": {
    "root": "session",
    "path": "Items[1]",
    "maxDepth": 2,
    "maxItemsPerCollection": 10
  }
}

Describe Type

Arguments:

  • typeName: required runtime type name
  • assemblyName: optional assembly name

Returns:

  • typeName
  • assemblyName
  • namespace
  • kind
  • baseType
  • interfaces
  • genericArity
  • memberVisibility
  • members
  • methods
  • capturedAtUtc

Example:

{
  "toolId": "reflect.describe_type",
  "arguments": {
    "typeName": "MyApp.DebugSessionViewModel",
    "assemblyName": "MyApp"
  }
}

Set Member Value

Arguments:

  • root: required registered root id
  • path: required allow-listed member path
  • valueJson: required JSON-encoded replacement value

Returns:

  • root
  • path
  • updated
  • snapshot
  • capturedAtUtc

The write path must end on a settable field or property. Collection-element writes such as Items[0] are not supported.

Example:

{
  "toolId": "reflect.set_member_value",
  "arguments": {
    "root": "session",
    "path": "SelectedTab",
    "valueJson": "\"details\""
  }
}

Invoke Method

Arguments:

  • root: required registered root id
  • targetPath: optional nested target path
  • method: required method name
  • parameterTypesJson: optional JSON array of parameter type names for overload disambiguation
  • argumentsJson: optional JSON array of argument values

Returns:

  • root
  • targetPath
  • signature
  • invoked
  • returnSnapshot
  • capturedAtUtc

Overloaded methods require parameterTypesJson. Nested targets use the same path grammar as reflect.inspect_object.

Example:

{
  "toolId": "reflect.invoke_method",
  "arguments": {
    "root": "session",
    "targetPath": "Child",
    "method": "Rename",
    "parameterTypesJson": "[\"System.String\"]",
    "argumentsJson": "[\"Updated Child\"]"
  }
}