Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Question] Support of struct as sub-types #987

Open
collectVood opened this issue Dec 9, 2022 · 9 comments
Open

[Question] Support of struct as sub-types #987

collectVood opened this issue Dec 9, 2022 · 9 comments

Comments

@collectVood
Copy link

Hi, are structs not supported as sub-types?

When serializing the struct sub type onto the stream I get the following error: System.InvalidOperationException: Unexpected sub-type: [..].Packets.TestPacket. The struct is serialized over the following method: Serializer.SerializeWithLengthPrefix(stream, (IPacket)testPacket, PrefixStyle.Base128);.
However serializing the Test Packet sub type as a class works without issues hence the question.

Example base interface:

[ProtoContract]
[ProtoInclude(100, typeof(TestPacket))]
public interface IPacket
{
}

Example struct sub type:

[ProtoContract(SkipConstructor = true)]
public struct TestPacket : IPacket
{
    [ProtoMember(1)] 
    public string Message;
}

Example class sub type:

[ProtoContract]
public class TestPacket : IPacket
{
    [ProtoMember(1)] 
    public string Message;
}
@buvinghausen
Copy link

buvinghausen commented Jan 6, 2023

@collectVood without reviewing the code as far as I know if it detects a struct it expects to find a concrete serializer rather than trying to read the properties

I was going to create an issue saying to support C# 9 record structs for the simple reason that I can create a positional record struct and it still have mutable properties which allow me databind it to a razor component form where if I use C# positional records they are init only and Razor will now allow property binding.

// Does not work
public readonly record struct IdResponse(Guid Id);

// Works great
public sealed record IdResponse(Guid Id);

I could see keeping the struct behavior as-is but adding support for record structs and honestly your implementation should be a record struct IMHO

link

For some added context when I boot my server if I put a record struct as either the request or response the server will not put it in the "RPC services being provided by" count but it still shows up in reflection then when I try to run it I get a 12 UNIMPLEMENTED error.

I favor the positional record syntax with gRPC because it is terse and concise but also because you don't have to decorate the class with the WCF/Proto attributes and set the order as it gets inferred from the constructor. You do need to be smart about not removing properties however esp if a 3rd party is using your gRPC services.

@mgravell
Copy link
Member

mgravell commented Jan 7, 2023

Right; there's two separate things here

  • struct records: we can look at - we support class records, and we'd certainly want struct records to work; I can investigate
  • structs as interface subtypes - honestly, interfaces as polymorphic base types has been more trouble that it was worth; I regret that we implemented it - it is a support nightmare; but: if something isn't working well in this case, we can again: have a look

But I suspect that they're two very different looks, if you see what I mean.

@mgravell
Copy link
Member

mgravell commented Jan 7, 2023

in my quick test of struct records, it looks to me like read-only works fine, and read-write currently fails - I will investigate:

image

@buvinghausen could you perhaps add some more details on what you mean here? what exactly happens? and with which library version?

// Does not work
public readonly record struct IdResponse(Guid Id);

mgravell added a commit that referenced this issue Jan 7, 2023
@mgravell
Copy link
Member

mgravell commented Jan 7, 2023

@buvinghausen mutable struct record support added in that branch (#1000); however, if it isn't already working, I wonder if you're using v2 - try making sure that you're targeting protobuf-net v3 latest

I'll investigate the interface sub-type scenario separately

@buvinghausen
Copy link

@mgravell I was getting an error when invoking the methods via postman let me see about getting a repro public repository up so we can go over the scenarios. There are just a couple of fringe cases that seem wonky and it would be awesome to get them ironed out.

For example if you use an array in a positional record it works just great in both the web client and server methods but the code first reflection errors out complaining about not knowing the value for Array_{{type}}.

@mgravell
Copy link
Member

mgravell commented Jan 8, 2023

@buvinghausen well, if you find some concrete failing tests: please be sure to log them as new issues; my plan is to use this issue to track @collectVood's report - have completed the analysis today, and it looks viable

@TieSKey
Copy link

TieSKey commented Jan 27, 2023

I'm also interested in having support for structs as interface subtypes.
I don't know the library's inner workings well enough to dare solve it myself but if there is anything more or less simple that needs to be done, please let me know.

@mgravell
Copy link
Member

I think I've done enough to prove to myself that we can do this - I have a branch on the laptop, I just need to finish it. Time is my enemy, but I hope to ship this within a couple of weeks.

@TieSKey
Copy link

TieSKey commented May 19, 2023

Hey, hi, just checking if there has been any news about this new feature.
Thx.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants