IAtsConvertable -- Allows custom De/Serialization across ATS boundaries#17473
IAtsConvertable -- Allows custom De/Serialization across ATS boundaries#17473cdbrown2018 wants to merge 7 commits into
Conversation
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 17473Or
iex "& { $(irm https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 17473" |
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Adds support for custom ATS conversion for “generic” objects by introducing an IAtsConvertable contract and wiring AtsMarshaller to call custom Deserialize logic, with a new test validating deserialization into a dictionary-backed DTO.
Changes:
- Introduce
IAtsConvertableandCustomAtsObjectDtoto support custom JSON ↔ object conversion across ATS boundaries. - Update
AtsMarshallerto detect ATS-convertible types and invoke their custom deserializer. - Replace an existing unmarshalling test with a new test for custom ATS object DTO deserialization.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 6 comments.
| File | Description |
|---|---|
| tests/Aspire.Hosting.RemoteHost.Tests/AtsMarshallerTests.cs | Adds test coverage for unmarshalling into CustomAtsObjectDto (but removes a prior init-list test). |
| src/Aspire.Hosting/Ats/AtsConvertable.cs | Introduces IAtsConvertable and CustomAtsObjectDto with dictionary-based JSON conversion logic. |
| src/Aspire.Hosting.RemoteHost/Ats/AtsMarshaller.cs | Adds detection and reflection-based invocation of Deserialize for ATS-convertible types. |
| if (IsIAtsConvertable(targetType)) | ||
| { | ||
| return targetType.GetMethod("Deserialize")?.Invoke(null, [jsonObj]); | ||
| } |
| public static JsonNode? Serialize(object value) | ||
| { | ||
| return JsonSerializer.Serialize(value); | ||
| } |
| public interface IAtsConvertable | ||
| { |
| /// Contains the result of deserialization. | ||
| /// </summary> | ||
| [AspireExportIgnore] | ||
| internal Dictionary<string, object?>? Object { get; set; } |
There was a problem hiding this comment.
This was intentionally marked internal because the property isn't meant to be read by consumers. It just represents the deserialized, generic object that was passed into the static Deserialize method. The only place that would be useful is in Aspire code that knows how to work with Dictionary<string, object?> such as manifest publishers. I'm open to discussion here.
| private static bool IsIAtsConvertable(Type type) | ||
| { | ||
| return type.GetInterfaces().Any(x => x.FullName == "Aspire.Hosting.Ats.IAtsConvertable"); | ||
| } |
There was a problem hiding this comment.
I'm not a fan of using a magic string either. However, the package references for Aspire.Hosting.RemoteHost are quite minimal, so I figured it wouldn't be acceptable to add a reference to Aspire.Hosting.Ats.
| [Fact] | ||
| public void UnmarshalFromJson_UnmarshalsCustomAtsObjectDto() |
There was a problem hiding this comment.
Yeah, not sure how this test got deleted, but good catch.
Description
Adds support for declaring custom Serialization and Deserialization logic across ATS boundaries.
Two types have been added --
IAtsConvertableandCustomAtsObjectDto.IAtsConvertableImplement this interface to provide custom de/serialization logic for a type that is exported over ATS. The Deserialize and Serialize methods are marked static as it is expected these methods will return an object of the type these methods are defined on.
IAtsConvertablewas added to the Unmarshalling logic, so anything that implements the interface will be deserialized accordingly.CustomAtsObjectDtoThis class provides a default implementation of the
IAtsConvertable. It simply takes aJsonObjectand deserializes it to aDictionary<string, object?>. The property is set to the class'sObjectproperty, to be used in SDK code. This allows completely custom objects to be sent across ATS boundaries, allowing client-code to specify their own objects. Particularly, this enables writing custom manifests for publishers, without having to make use of extension methods, and using the AppHost language's native object creation semantics.An example of how this type is used is available in the #17074 PR.
Checklist
<remarks />and<code />elements on your triple slash comments?