I'm trying using gRPC dynamically typed values but with the little information about their usefulness, It's almost impossible to do this... So I will show the image/code that I have problems and the questions that are eating my brain
gRPC Method I'm doing:
public override Task<HelloReply2> TestObject(Status request, ServerCallContext context) {
//The part I may have problems
var status = new Status();
//here I want a User that corresponds to my request.Data
//example -> request.Data = User1 (gives me null if User1 don`t exist in db)
// request.Data = 14 (gives me null if 14 don`t exist in db)
// request.Data = true (gives me null if true don`t exist in db)
var a1 = _context.Users_5.FirstOrDefault(x => x.Username.Equals(request.Data));
var b1 = _context.Users_5.FirstOrDefault(x => x.Email.Equals(request.Data));
var c1 = _context.Users_5.FirstOrDefault(x => x.Age.Equals(request.Data));
var d1 = _context.Users_5.FirstOrDefault(x => x.Test.Equals(request.Data));
//is a bool
//here i want too Create dynamic values
status.Data = Value.ForStruct(new Struct {
Fields =
{
["Integer"] = Value.ForNumber(c1!.Age),
["StringName"] = Value.ForString(a1!.Username),
["StringEmail"] = Value.ForString(b1!.Email),
["Boolean"] = Value.ForBool(d1!.Test)
}
});
//Below is just a simple string who gives different string (depending on the
//data Status (also how to read the message from the status.Data ?)
HelloReply2 hello = new();
if(a1 != null)
{
hello.Message = "There is a User with the Username " + request.Data + ". His Email is " + a1.Email;
} else if (b1 != null) {
hello.Message = "There is a User with the Email " + request.Data + ". His Username is " + b1.Username;
}
else if (c1 != null)
{
hello.Message = "There is at least one User with that Age of " + request.Data + ". His Username is " + c1.Username;
}
else if (d1 != null)
{
if(d1.Test == true)
{
hello.Message = "There is at least one User who dislikes chocolate: " + request.Data + ". His Username is " + d1.Username;
} else
{
hello.Message = hello.Message = "There is at least one User who likes chocolate: " + request.Data + ". His Username is " + d1.Username;
}
}
else
{
hello.Message = "We didn't find something with the value that the User put in. Value:" + request.Data;
}
return Task.FromResult(hello);
}
Questions: How to Get the one Value from my gRPC? How to convert a "Object" in c# (one string, one integer or one List) into a ONE value of google.protobuf.Value (so it not give me errors like this Controller from a Web Api below)? Is something wrong with my gRPC Service Method (is something wrong reading the dynamic values? Can I do that calls for getting a User for a DB? How to read dynamic values?)
// I try using Google.Protobuf.WellKnownTypes.Value obj but
//not workings because gives me a lot of values to put
[HttpGet("TypeObject/{obj}")]
public async Task<ActionResult<HelloReply2>> TypeObject([FromRoute] Object obj){
Status objRequest = new Status { Data = (Google.Protobuf.WellKnownTypes.Value)
obj };
//cannot do this (gives me error of casting but the ideia is doing something
//similar to this)
var hello = await _greetClient.TestObjectAsync(objRequest);
return Ok(hello);
}
Any help on how to resolve this error of using Value gRPC or if is something wrong with the code is always welcome.
Edit:
One day after this question I don't have any solutions / progress. I was think of doing Any or OneOf for testing but it also gives me errors (who don't make sense at all). This code from Microsoft (C# Format part is not recognize) doesn't work in my project with the protos reload (the problem is not in the protos)
Link: https://learn.microsoft.com/en-us/dotnet/architecture/grpc-for-wcf-developers/protobuf-any-oneof
How I can use Any / OneOf without give me error in the Formating? What is the difference between Value and this two? Can the three (Value, Any, OneOf) be dynamic/Object values (if yes how to convert the types)?
Edit 2:
Still have problems, I'm trying using gRPC Any , and maybe have some progress (not all).
So with Any I have my method in the server gRPC and it is like this
public override Task<HelloReply2> TestObject3(AnyMessage request, ServerCallContext context){
HelloReply2 anyMessageResponse;
var y = request.TypeUrl;
switch (request.TypeUrl)
{
case "type.googleapis.com/any.HelloRequest":
var string_1 = request.Unpack<HelloRequest>();
anyMessageResponse = new HelloReply2{
Message = "You type String: " + $"{string_1.Name}"
};
break;
case "type.googleapis.com/any.TestInteger1":
var integer_1 = request.Unpack<TestInteger1>();
anyMessageResponse = new HelloReply2{
Message = "You type Integer: " + $"{integer_1.Message}"
};
break;
case "type.googleapis.com/any.TestBool1":
var bool_1 = request.Unpack<TestInteger1>();
anyMessageResponse = new HelloReply2{
Message = "You type Bool: " + $"{bool_1.Message}"
};
break;
default:
throw new InvalidOperationException("Unexpected type URL.");}
return Task.FromResult(anyMessageResponse);
}
This ideia comes from here (https://github.com/grpc/grpc-dotnet/issues/917), but the client part their don't have any much info or I don't understand that part
This is what I did in the WebApi (who is my client and the code is similar to the above one)
using AnyMessage = Google.Protobuf.WellKnownTypes.Any;
[HttpGet("TypeObject3/{obj3}")]
public async Task<ActionResult<HelloReply2>> TypeObject3([FromRoute] string obj3)
{
AnyMessage objRequest = new() { TypeUrl = obj3 };
var hello = await _greetClient.TestObject3Async(objRequest);
var l = hello.Message;
return Ok(hello);
}
First I had the variable Any declared in the method instead of string but as you can only put string and stringBytes so I preferred to put it like this (with the string as an obj3 variable) but my goal is to see if the variable is of type TestBool1 or TestInteger1 as I have declared in the protos and not be a string that I will be able to see, and the biggest problem was if I had more variables inside the messages how to proceed? So my secondary question is how to use Any on the client side via the Web-Api? I forgot to say but I'm using .Net 6 Core and for testing I'm using Swagger, where at this moment my error hits the Exception dictated by the Server method.
Questions: Why TypeUrl is a string and not object? How to fix my problem? How to test the object type (or string) for more values if the messages was with 1 more types?
Also I will show my test proto too show how I'm doing this
import "google/protobuf/struct.proto";
import "google/protobuf/any.proto";
package greet;
// The greeting service definition.
service Greeter {
// Sends a greeting
rpc SayNormalHello (Empty_2) returns (HelloReply);
rpc SayHello (HelloRequest) returns (HelloReply2);
rpc TestInt (TestInteger1) returns (HelloReply2);
rpc TestBoolean (TestBool1) returns (HelloReply2);
rpc TestObject (Status) returns (HelloReply2); //Not working
rpc TestObject2 (Status2) returns (HelloReply2); //Not working
rpc TestObject3 (google.protobuf.Any) returns (HelloReply2); //Also
//Not working
}
message Empty_2{
}
// The request message containing the user's name.
message HelloRequest {
string name = 1;
}
// The response message containing the greetings.
message HelloReply {
string message = 1;
}
// The response message containing the greetings.
message HelloReply2 {
string message = 1;
}
message TestInteger1 {
int32 message = 1;
}
message TestBool1 {
bool message = 1;
}
message Status {
google.protobuf.Value data = 1;
}
message Status2 {
google.protobuf.Any data = 1;
}
Any help is welcome.

In the project I developed, I needed an infrastructure where I could perform dynamic operations such as REST service using gRPC. As I understand it, what you want is something similar to this.
I have developed a solution for this. It might work for you too.
You can gain some flexibility by making a definition with a single String field for Requests and Responses that you want to be Dynamic, and then using this field to hold JSON data as strings.
For example, instead of defining different responses for different types, you can solve it by making one definition like this.