Class AsmdefReferenceWriter
Resolves the asmdef reference sets a generated service extension's layers need, writes brand-new
layered asmdefs (the code layer, Installation, and Tests each own their folder — no existing asmdef is
ever mutated), and appends the PipelineReplace task to the project's initialization pipeline profile.
Inheritance
AsmdefReferenceWriter
Assembly: Serenity.ServiceExtensionCreator.Editor.dll
Syntax
public static class AsmdefReferenceWriter
Methods
AppendTaskToProfile(UnityInitializationPipelineProfile, UnityReflectionCallTaskDefinition, out string)
Declaration
public static bool AppendTaskToProfile(UnityInitializationPipelineProfile profile, UnityReflectionCallTaskDefinition taskDefinition, out string warning)
Parameters
Returns
CreateAsmdef(string, string, string, IReadOnlyCollection<string>, bool)
Writes a brand-new asmdef at {folderPath}/{assemblyName}.asmdef — every generated layer owns
its own folder, so this never mutates an existing asmdef. testAssembly applies
the shape every generated test asmdef in this project shares (mirrors Assets/Serenity/Tests/Tests.asmdef):
an nunit precompiled reference, the UNITY_INCLUDE_TESTS define constraint, overridden
references, and not auto-referenced.
Declaration
public static string CreateAsmdef(string folderPath, string assemblyName, string rootNamespace, IReadOnlyCollection<string> references, bool testAssembly = false)
Parameters
Returns
ExtensionPointInstallationReferences(ExtensionPointDescriptor, Style, string, bool, Type)
The asmdef reference names a generated Store/Repository/Gateway/Installer Installation layer needs:
everything the code layer needs (when one was generated — the Installer kind has none),
codeLayerAssemblyName itself (for the generated class type the wiring
constructs), and every assembly in wiringBaseType's own base-class chain — the
type the wiring subclasses (the aggregate's Unity{X}Installer for Repository/Gateway, or
PersistenceInstaller for Store/Installer). The base-class chain matters because the C#
compiler must resolve a named base type's OWN base classes too (CS0012 fires otherwise) — e.g.
UnityScoreInstaller lives in Serenity.UnityScore.Installation but its base
ScoreInstaller lives in the separate Serenity.Score.Installation assembly, and Unity
asmdef references are not transitive.
Declaration
public static IReadOnlyCollection<string> ExtensionPointInstallationReferences(ExtensionPointDescriptor descriptor, ServiceExtensionCreator.Style style, string codeLayerAssemblyName, bool hasCodeLayerClass, Type wiringBaseType)
Parameters
Returns
HasTestFrameworkAccess(string)
True when the asmdef governing folder (or Assembly-CSharp when none governs it)
already exposes NUnit/TestRunner access — the cheap, generically-detectable signal for whether a
generated test stub would actually compile when Skip
leaves it joining the ambient assembly instead of a dedicated generated Tests asmdef.
Assembly-CSharp itself is assumed to lack this access, matching this project's convention of never
enabling "Test Assemblies" for it.
Declaration
public static bool HasTestFrameworkAccess(string folder)
Parameters
| Type |
Name |
Description |
| string |
folder |
|
Returns
InstallationReferences(AggregateDescriptor, Style, Wiring, string)
The asmdef reference names the generated Installation layer needs: everything the code layer needs
directly — Unity asmdef references are NOT transitive, so referencing codeLayerAssemblyName
alone would not re-expose Serenity.Global.Application or the aggregate's interface assembly
to the wiring script that names them directly — plus codeLayerAssemblyName itself
(for the constructed service type), and, for PipelineReplace, the assembly hosting
UnityReflectionCallTaskDefinition so a hand-written extension of the generated wiring can
reach the task type without a manual asmdef edit.
Declaration
public static IReadOnlyCollection<string> InstallationReferences(AggregateDescriptor descriptor, ServiceExtensionCreator.Style style, ServiceExtensionCreator.Wiring wiring, string codeLayerAssemblyName)
Parameters
Returns
RequiredReferences(AggregateDescriptor, Style, Wiring)
The asmdef reference NAMES the generated code layer (Business/Application or Infrastructure) needs.
Resolved from the actual compiled assemblies via reflection rather than a naming convention —
several Serenity modules (GameSettings, EventDispatcher, FilePersistence, ServiceLocator, Logging
among them) fold their Application layer into Serenity.Global.Application via .asmref
instead of shipping their own asmdef, so a convention-based "Serenity.{Agg}.Application" guess
would be wrong for those. "Serenity.Global.Application" is always included: it hosts
IService/ILogService/IServiceLocator/AutoRegisterServiceAttribute.
"Serenity.Global.Domain" is always included too: IService : IFoundationSettings, and
IFoundationSettings lives in that separate assembly — a generated class implementing (or a
wiring script referencing) any I{X}Service touches it transitively through the interface
hierarchy, and Unity asmdef references are NOT transitive, so it must be listed explicitly. Neither
is re-exposed by referencing the aggregate's own interface assembly alone. On top of that fixed set,
every assembly touched by the generated members' SIGNATURES is unioned in — the same
Serenity.ServiceExtensionCreator.Editor.AsmdefReferenceWriter.CollectMemberAssemblyNames(System.Collections.Generic.IReadOnlyList{System.Reflection.MemberInfo}) collector the extension-point kinds use: the interface
members for every style (e.g. IScoreService's members name ScoreKey/ScoreSnapshot
from the separate Serenity.Score.Domain assembly, which the fixed set alone omits — a real
field-tested CS0246/CS0012), plus — for InfrastructureSubclass — the concrete base's public virtual
member and constructor signatures and its base-class chain (Serenity.ServiceExtensionCreator.Editor.AsmdefReferenceWriter.CollectSubclassBaseAssemblyNames(System.Type)),
since the generated overrides and forwarding constructors restate those signatures in source.
Declaration
public static IReadOnlyCollection<string> RequiredReferences(AggregateDescriptor descriptor, ServiceExtensionCreator.Style style, ServiceExtensionCreator.Wiring wiring)
Parameters
Returns
RequiredReferences(ExtensionPointDescriptor, Style, Type)
The asmdef reference names a generated Store/Repository/Gateway/Factory code layer needs: the
contract's own assembly, the subclassed base's assembly plus its base-class chain and restated
member/constructor signature assemblies when subclassing (InfrastructureSubclass style — the base is
subclassBaseOverride when the user picked one, the descriptor's reference
concrete otherwise), and — unlike RequiredReferences(AggregateDescriptor, Style, Wiring),
which leans on every Serenity service interface's members staying within its own assembly boundary
— every assembly touched by the contract's own member signatures (Serenity.ServiceExtensionCreator.Editor.AsmdefReferenceWriter.CollectMemberAssemblyNames(System.Collections.Generic.IReadOnlyList{System.Reflection.MemberInfo})),
since some modules (e.g. Score: Serenity.Score.Application vs Serenity.Score.Domain)
split their interface from its parameter/return DTO types across two real, separate assemblies.
No assembly is unconditionally included — these contracts do not extend IService, so there is
no Serenity.Global.Application/Serenity.Global.Domain dependency to guarantee.
Declaration
public static IReadOnlyCollection<string> RequiredReferences(ExtensionPointDescriptor descriptor, ServiceExtensionCreator.Style style, Type subclassBaseOverride = null)
Parameters
Returns
ResolveNearestAssemblyName(string)
Walks up from folder to the nearest .asmdef and returns its assembly
name, or "Assembly-CSharp" when no asmdef governs the folder. Mirrors ModalCreator.ResolveAssemblyName.
Used to resolve the ambient assembly a generated file joins when Skip
leaves no dedicated asmdef behind.
Declaration
public static string ResolveNearestAssemblyName(string folder)
Parameters
| Type |
Name |
Description |
| string |
folder |
|
Returns
TryResolvePipelineProfileName(out string, out string)
Declaration
public static bool TryResolvePipelineProfileName(out string profileName, out string warning)
Parameters
Returns
TryResolveSingleProfile(out UnityInitializationPipelineProfile, out string)
Resolves the project's single UnityInitializationPipelineProfile asset, without
mutating anything — the robust signal for "this is the profile the game actually uses" without
depending on a scene being open or on UnitySerenityInstaller (which lives in Assembly-CSharp
and cannot be referenced from this asmdef). Ambiguous or missing profiles return false with an
explanatory warning that lists every candidate asset path when more than one was found.
Declaration
public static bool TryResolveSingleProfile(out UnityInitializationPipelineProfile profile, out string warning)
Parameters
Returns