Release v20.61.0
Added
ARC0014analyzer diagnostic: a generic static method on a[ReadModel]whose return type matches a query shape is reported at compile time, since query discovery would register it as an endpoint that can never be invoked. It inspects internal methods as well as public ones, matching what discovery actually registers.QueryMethodCannotBeGeneric, thrown byModelBoundQueryPerformer's constructor, so a generic query method fails at wire-up naming the offending method rather than per request with a bare reflection message.
Fixed
- FluentValidation rules now reach generated client proxies. No rule had ever been projected: generation walks the target project through a
MetadataLoadContext, whose types carry no executable code, while a FluentValidation rule only exists once its validator's constructor has run — so instantiating the validator always threw, and the catch turned that into "no rules". Every extractor spec passed because they hand it runtime types, which the generator never has. Validator types are now resolved in the default load context and instantiated there. DataAnnotations were unaffected, being read from metadata. - A validation message declared lazily —
.WithMessage(_ => Messages.Something), the form a localized message takes — is held as a factory rather than a string and was dropped. It is now resolved where it does not depend on the instance, and left unprojected rather than guessed at where it does. - The proxy generator's
AssemblyLoadContext.Defaultresolving hook handed back a metadata-only assembly, which throwsResolved assembly must be a runtime Assembly object. Caching that assembly is the point of the hook; returning it was not. - A generic static method on a
[ReadModel]is no longer discovered as a query. Discovery matches on return type alone, so a generic composition helper returning the read model's own query shape was registered, routed, and given a client proxy — and then every call failed withLate bound operations cannot be performed on types or methods for which ContainsGenericParameters is true. Rejected now at the shared runtime predicate, its copy in the proxy generator, and the metadata generator.
Changed
Cratis.Arc.ProxyGenerator.Buildtakes a framework reference onMicrosoft.AspNetCore.App. Reading validation rules loads the target project's own assembly for real, and targets are ASP.NET applications, so that load fails without the shared framework.
Verified end to end against a real application's assembly, not only in specs: 83 generated proxies gained a validator where previously 0 carried one, with concept-level rules attributed to the owning command property and their localized messages resolved; the generic read model helper's dead client proxy and its route are gone.
Both fixes were confirmed to have teeth by reverting them and watching the new specs fail. Full suite green: 3,962 passed, 0 failed.
🤖 Generated with Claude Code