ZuloOne
English
Sign in
Menu

Partial Scripts & Resources (MIQS two-part scripts)

Updated

Two-part scripts#

A user script that declares a partial class is compiled together with a generated framework part — the MIQS pattern of "generated shell + editable business logic", adapted to the web stack. The framework is deterministic and never stored: RuntimeCompiler.CompileAsync regenerates it on every compile, so platform upgrades reach all scripts at once.

The pairing is implemented in ZuloOne.Runtime/ScriptFramework.cs:

  • GlobalUsings.cs — C#10 global using for System.*, all ZuloOne.Runtime.* namespaces, ZuloOne.Core.Services and (when the generated-entities assembly is referenced) ZuloOne.Runtime.Generated. User partials carry no using block at all.
  • Framework.cs — a partial class X counterpart for every partial class in the user source, emitted into the same namespace (parsed from the user code — event handlers stay in ZuloOne.Runtime.Generated by contract). It carries the shared helpers, currently GetResource(key, culture?).
  • script.cs — the user code, path preserved so compile errors and PDB stack frames still point at what the user typed.

The user part owns the base-type declaration (public partial class Handler : CommandHandlerBase), which keeps the framework template universal across all script types (event handlers, transactions, commands, services, reports, jobs, tests, print forms). All starter templates in the frontend produce this form.

Scripts without partial compile exactly as before — the framework is skipped, so ad-hoc/legacy full classes keep working.

The code editor (CodeEditorWorkbench, partialTools) shows three main tabs: Script text | Framework | Resources. Framework is fetched from POST /api/metadata/scripts/framework (read-only preview of the generated part for the current code).

Resources#

Per-script localized texts (MIQS ScriptResource / ScriptID): MetaResources table (ScriptMetaId = owning script or integration test, Name unique inside that owner, Value default/EN, ValueRu, ValueAr). Unscoped rows (ScriptMetaId null) remain on Developer → Resources and are the fallback.

  • CRUD: /api/metadata/resources?scriptId= (the Resources tab of the open script) and /api/metadata/resources (unscoped catalogue).
  • Runtime store: ZuloOne.Runtime.Resources.ResourceStore — process-wide map reloaded by ResourceStoreLoader at startup and after every change; lookup is owned key → unscoped key → the key itself. Culture fallback: requested → default → the key.
  • Request language: the SPA sends X-ZuloOne-Lang; middleware in Program.cs sets ResourceStore.CurrentLanguage (AsyncLocal), so UserMessages-style texts localize per user.
  • Scripts read resources two ways:
    • GetResource("Key") — framework helper, any string key;
    • Res.Key — strongly-typed class generated into the entities assembly by MetadataCompilerService.CompileAllAsync (ScriptFramework.BuildResourceClass). Text edits are live (values resolve through the store); only new keys need a metadata recompile to appear on Res.

Tests: ZuloOne.Tests/PartialScriptsTests.cs, e2e frontend/e2e/resources.spec.ts.

Was this page helpful?