Point two Studios at two roots without fighting
XPP_AOT_ROOT wins over every other root resolution — so a shortcut with the
variable set gives you a second, independent instance pointed at another
metadata folder (e.g. a UAT copy) without touching your saved setting.
Search before the index converges — deliberately
Element and method-name lookup is complete from tier 2. If you’re hunting a
call site by name, you don’t need to wait for the FTS tail; if you’re hunting a
string in method bodies, check the partial flag first — a negative answer
before convergence proves nothing.
The nuclear option for a weird index
Full re-index on every launch usually means a fingerprint mismatch or a
locked/corrupt cache DB. Read the [aot] log lines once, then delete
%APPDATA%\xpp-studio\aot-index\<hash>.db and let it rebuild clean — minutes
now instead of seconds-every-launch forever.
Let the compiler tell the truth about event handlers
A generated SubscribesTo handler whose delegate doesn’t exist yet fails the
first build with the compiler’s own message — identical to Visual Studio.
That’s not a scaffolding bug; add the delegate and rebuild. The Studio never
smooths over real compiler feedback.
Prove your pipeline locally before pushing YAML
The CI scaffold’s build and test stages are the Studio’s own headless
invocations. A green in-IDE Build Model + a green local SysTest run is the same
fact as a green pipeline — fill TestClasses in Azure DevOps only after both
are green on the VM.
Portable zip for side-by-side versions
Keep the current release installed and drop the previous version’s portable zip
beside it. Settings and index caches live in %APPDATA%, shared and safe —
nothing to uninstall, nothing to break.
Deploy is elevated — plan for it
The deploy pipeline gates on administrator rights by design and fails fast.
If you schedule deploys, launch the Studio elevated before the change window,
not after the pipeline refuses.
Debugging .NET Framework code? Use the host pattern
net48 companions can’t be debugged directly (the adapter is CoreCLR-only), but
the same code is fully debuggable when called from a .NET 8 host — breakpoints,
stepping into library frames, conditional breakpoints across the boundary.
Structure the interop as net48 library + net8 host and nothing is lost.
Signature drift? Re-scaffold, don’t hand-fix
If a CoC wrapper’s signature no longer matches the target method, the fastest
correct fix is deleting the wrapper and re-scaffolding from the AOT explorer —
the generator re-derives the exact signature. Hand-editing signatures is how
subtle runtime skips happen.
Set your naming prefix once
wizardNamePrefix in settings.json gives every wizard-generated artifact your
team’s prefix (e.g. Contoso) with no forced convention — set it once per
environment and naming reviews get shorter.
The collision refusal is a feature
A wizard that refuses to commit because “a form named X already exists in
model Y” just saved you a silent overwrite. The same guard refuses to touch an
existing file on disk — if it fires, read it as protection, not friction.
Dotted names are for table extensions only
The identifier validator allows dots exactly one place — table extensions
(<Table>.<Suffix>). Everywhere else it’s a clean identifier. If a dotted
name is rejected, you’re naming the wrong artifact kind.