Correct object (type) deserialization in .NET polyglot notebooks

I’m building a library with a lightweight Speckle API.
I want to be able to filter through a Stream’s objects for specific types, as recorded in their speckle_type attribute (as strings)

When I view the object in the viewer, the speckle_type is correct (e.g. “Objects.Geometry.Brep”)

However, when I retrieve the object via API, the speckle_type seems to revert to “Base”

Is there a way to maintain the correct speckle_type value of the object when using the API?

Hey @daniel-fink ,

In order to get their types, you need to first deserialize the objects received from the API, then something like this.GetType().Name should give you the actual class/name.

Thanks for the quick reply @teocomi.

Unfortunately I still get “Speckle.Core.Models.Base” on performing .GetType() on this object.

Is it something to do with the .Flatten() method that has internal casts to Base? I notice that the speckle_type property of the Base class has a dynamic getter that composes the string from .GetType()…?

In any case, why does the viewer app produce the correct speckle_type (in the example – “Objects.Geometry.Brep”) while my C# code does not?

If the objects are not deserialised to their correct .net types, they deserialise to base, and you get that type.

They viewer does not deserialise to any concrete types, and as such just uses the raw value, which is correct.

The question becomes then:

  • when you get objects back from the server, how do you do it?
  • do you deserialise them?
  • if yes, is the objects kit loaded?

Thanks @dimitrie.
I’m using the Speckle.Core.Api helpers which (correct me if I’m wrong) do the deserialization for me?
I’m not sure what you mean by loading the objects kit. On getting a commit I do see a message that a ‘Kit Manager’ was initialized–

var commit = client.CommitGet("c0f66c35e3", "9a9670946f").Result;
var root = Operations.Receive(commit?.referencedObject, transport).Result;

Results in:

[22:25:34 INF] Initialized logger inside Coreunknown/2.18.0/2.18.0.13567 for user 91C733C10DF1496893028551A8BB138C. Path info /Users/daniel/Library/Application Support /Users/daniel/Library/Application Support.
[22:25:34 INF] Initializing a new Remote Transport for https://speckle.xyz/
[22:25:34 DBG] Starting execution of graphql request to get StreamData
[22:25:34 DBG] Starting execution of http request to https://speckle.xyz/graphql
[22:25:34 INF] Execution of http request to https://speckle.xyz//graphql succeeded with OK after 0.9099276 seconds and 0 retries
[22:25:34 INF] Execution of graphql request to get StreamData succeeded after 0.9457364 seconds
[22:25:34 INF] Starting receive e7acaac21ae7e9369339900a4aaeb827 from transports SQLite / RemoteTransport
[22:25:35 INF] Initializing Kit Manager in /Users/daniel/Library/Application Support/Speckle/Kits
[22:25:35 INF] Finished receiving e7acaac21ae7e9369339900a4aaeb827 from RemoteTransport in 0.4712478 seconds

Once there, I simply flatten all children and find a match for the object’s Id I’m looking for:
var children = root.Flatten().ToList();
var foo = children.First(item => item.id == "ef629b7b125e750815bb25d0e209b675");

foo["speckle_type"] gives me “Base”…

If I haven’t loaded the Objects Kit, how do I do so?

You can add a direct reference to the Objects.dll or use its nuget package - let us know if this does it!

I’m working in dotnet interactive (Polyglot Notebooks). Could that be the issue?
I’ve loaded the nuget packages with

#r "nuget: Speckle.Core, *-*"
#r "nuget: Speckle.Objects, *-*"

And I can even construct an arbitrary Speckle Point with the Objects Kit, but still the speckle_type is “Base”

To frame the question another way:
How can I deserialize this object (which is an “Objects.Geometry.Brep” according to the webviewer), into an instance of a Objects.Geometry.Brep using the Speckle C# libraries?

I think you’re doing everything right, and it might be due to the environment provided by polyglot notebooks; .NET lazy loads assemblies on need, so at the point of deserialisation the objects kit is not actually loaded yet. I might be wrong, and I have no clue how assemblies are managed in that environment :upside_down_face:

Could you create that point within the same codeblock where you’re receiving things, just before the actual code (commit get, operations receive)?

The last thing is for us to try and reproduce locally if this doesn’t work out.

2 Likes

Thanks @dimitrie! Utilizing the Objects Kit in the same cell as a deserialization operation (e.g. with .Receive()) does produce accurate typing of objects, so it seems like it’s to do with how dotnet loads assemblies as needed within a notebook’s cells.

Not sure what an overall fix for Speckle might look like if use of notebooks is more generally supported (maybe some way of inviting a user to specify namepsaces/assemblies for use during deserialization?)

1 Like

Happy to hear it worked out! I’m not sure there’s a proper “fix” from our end - it would mean doing things against how .NET is meant to work, even though it’s what you would expect in a code notebook.

What I can do is edit the title of this post and have it read loud and clear what we solved for so others can find it down the line.