Reflection
Register the reflection tool suite to list registered roots, inspect live object state, describe runtime types, set writable members, and invoke reachable instance methods.
Warning: This suite includes Critical tools and can inspect live runtime state, mutate writable members, or invoke reachable instance 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 --prerelease
Register the Suite
using Ansight;
using Ansight.Tools.Reflection;
var session = new DebugSessionViewModel();
using var sessionRoot = ReflectionRootRegistry.Register(
"session",
session,
new ReflectionRootMetadata("Current Session")
{
Description = "Active session view model",
Hints = ["debug", "session"]
},
ReferenceType.Strong);
var options = Options.CreateBuilder()
.WithReflectionTools(reflection =>
{
reflection.WithDefaultMemberVisibility(ReflectionMemberVisibility.PublicOnly);
reflection.WithAssemblyTraversalMode(ReflectionAssemblyTraversalMode.AllowListedOnly);
reflection.WithNamespaceTraversalMode(ReflectionNamespaceTraversalMode.AllowListedOnly);
reflection.AllowNamespacePrefix("MyApp.ViewModels");
})
.WithReadWriteToolAccess()
.Build();
Registration API
ReflectionRootRegistry.Register(string id, object target, ReflectionRootMetadata metadata, ReferenceType referenceType = ReferenceType.Weak): registers a live object root.ReflectionRootRegistry.Register(string id, Func<object?> targetGetter, ReflectionRootMetadata metadata): registers a root that is resolved on each call.ReflectionRootRegistry.Deregister(string id): removes the current root for an id.ReflectionRootRegistrationHandle.Deregister()/Dispose(): removes the exact registration returned byRegister(...).WithReflectionTools(): registers the suite with default reflection options.WithReflectionTools(reflection => ...): configures traversal and visibility while registering the suite.WithReflectionTools(ReflectionToolsOptions): registers the suite with an options object.WithAssemblyTraversalMode(...): chooseAllowAllorAllowListedOnlyfor assembly-based traversal boundaries.WithNamespaceTraversalMode(...): chooseAllowAllorAllowListedOnlyfor namespace-based traversal boundaries.AllowAssembly(...)/AllowAssemblies(...): add assembly allow-list entries when assembly traversal isAllowListedOnly.AllowNamespacePrefix(...)/AllowNamespacePrefixes(...): add namespace-prefix allow-list entries when namespace traversal isAllowListedOnly.WithDefaultMemberVisibility(...): set the global visibility rule. The default isPublicOnly.
The current simplified surface does not include per-root member or method allow-list APIs. Choose narrow roots, traversal boundaries, member visibility, and runtime guard policy instead.
Root Metadata
ReflectionRootMetadata requires DisplayName and also supports:
DescriptionHints
Specific Concerns
- The suite never reflects arbitrary process objects. Apps must register every root explicitly.
- Direct object roots use weak references by default. Pass
ReferenceType.Strongonly when the root must stay alive for the lifetime of the suite. - Getter roots resolve the object every time a tool runs and report unavailable when the getter returns
nullor throws. - Expansion is stateless. Every call resolves from the root again rather than using persistent object handles.
- Recursive traversal is open by default. Use
AllowListedOnlytraversal modes withAllowAssembly(...)andAllowNamespacePrefix(...)when you need to restrict expansion. - Types outside configured allow-list boundaries 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_valueandreflect.invoke_methodareWritetools. They requireWithReadWriteToolAccess()or a customToolGuard.- Writes still require the target field or property to be writable.
- Collection-element writes and static method invocation are out of scope in v1.
If you want restricted traversal within registered roots, opt in explicitly:
reflection.WithAssemblyTraversalMode(ReflectionAssemblyTraversalMode.AllowListedOnly);
reflection.WithNamespaceTraversalMode(ReflectionNamespaceTraversalMode.AllowListedOnly);
reflection.AllowAssembly("MyApp");
reflection.AllowNamespacePrefix("MyApp.ViewModels");
Path Syntax
Property.SubProperty[index]["key"]
Tool Matrix
| Name | Id | Scope | Description | Security |
|---|---|---|---|---|
List Reflection Roots | reflect.list_roots | Read | Lists registered live object roots, metadata, and availability. | High |
Inspect Object | reflect.inspect_object | Read | Returns a stateless snapshot of a registered live object or nested path. | Critical |
Describe Type | reflect.describe_type | Read | Returns runtime type metadata without reading live object values. | Moderate |
Set Member Value | reflect.set_member_value | Write | Writes a settable field or property reachable from a registered root. | Critical |
Invoke Method | reflect.invoke_method | Write | Invokes an instance method reachable from a registered root. | Critical |
List Reflection Roots
Arguments:
- none
Returns:
rootscountcapturedAtUtc
Each root descriptor includes:
idmetadatareferenceTypeavailableruntimeTypememberVisibilityresolutionError
Example:
{
"toolId": "reflect.list_roots",
"arguments": {}
}
Inspect Object
Arguments:
root: required registered root idpath: optional nested member or collection pathmaxDepth: recursive expansion depth, default1, maximum4maxItemsPerCollection: collection item limit, default10, maximum64
Returns:
rootpathsnapshotcapturedAtUtc
Snapshot payloads include common fields such as:
declaredTyperuntimeTypekindisNullpreviewexpandable
Expanded snapshots may also include:
membersmethodsitemstruncatedopaquecycleDetected
Example:
{
"toolId": "reflect.inspect_object",
"arguments": {
"root": "session",
"path": "Items[1]",
"maxDepth": 2,
"maxItemsPerCollection": 10
}
}
Describe Type
Arguments:
typeName: required runtime type nameassemblyName: optional assembly name
Returns:
typeNameassemblyNamenamespacekindbaseTypeinterfacesgenericAritymemberVisibilitymembersmethodscapturedAtUtc
Example:
{
"toolId": "reflect.describe_type",
"arguments": {
"typeName": "MyApp.DebugSessionViewModel",
"assemblyName": "MyApp"
}
}
Set Member Value
Arguments:
root: required registered root idpath: required member pathvalueJson: required JSON-encoded replacement value
Returns:
rootpathupdatedsnapshotcapturedAtUtc
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 idtargetPath: optional nested target pathmethod: required method nameparameterTypesJson: optional JSON array of parameter type names for overload disambiguationargumentsJson: optional JSON array of argument values
Returns:
roottargetPathsignatureinvokedreturnSnapshotcapturedAtUtc
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\"]"
}
}