Hello,
I’m trying to test a NetCore Grpc web service with Oxygene and Water but Water doesn’t recognize the proto file.
What did I miss
First i hear of grpc and “proto” files, so if those are files that Water or our build chain would have to do something special with, what you’re missing is probably that we don’t have support for this ;).
Do you have test-case project and/or any links so I could have a look at what is needed here?
thanx,
marc
Great!
What exactly do you want?
I have a working source test in c# and the one with Water de base not working.
My goal is to use Oxygene for an HTTP/3 server with Google Protobuf protocol ( https://grpc.io )
Norbert
Getting both of this projects would be a great start.
Oops, sorry for the delay.
I quickly rewrote a server and a console client in Visual Studio 2022.
7z file attached
Thanks in advance for taking the time to look at it.
Sincerely,
Norbert
Grpc.7z (101.9 KB)
To start off, I’ve added .proto
to list of known text file types, for Fire/Water.
That said, your project seems to build and run fine, and serves at http://localhost:5000. What errors/problems should I be looking for?
the class proto3 are not generated (Generated by the protocol buffer compiler cf: project VS2022) and therefore not accessible to work with Water
Souce VS auto generated
type or paste code here// <auto-generated>
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: Protos/greet.proto
// </auto-generated>
#pragma warning disable 0414, 1591, 8981
#region Designer generated code
using grpc = global::Grpc.Core;
namespace GrpcService1 {
/// <summary>
/// The greeting service definition.
/// </summary>
public static partial class Greeter
{
static readonly string __ServiceName = "greet.Greeter";
[global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
static void __Helper_SerializeMessage(global::Google.Protobuf.IMessage message, grpc::SerializationContext context)
{
#if !GRPC_DISABLE_PROTOBUF_BUFFER_SERIALIZATION
if (message is global::Google.Protobuf.IBufferMessage)
{
context.SetPayloadLength(message.CalculateSize());
global::Google.Protobuf.MessageExtensions.WriteTo(message, context.GetBufferWriter());
context.Complete();
return;
}
#endif
context.Complete(global::Google.Protobuf.MessageExtensions.ToByteArray(message));
}
[global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
static class __Helper_MessageCache<T>
{
public static readonly bool IsBufferMessage = global::System.Reflection.IntrospectionExtensions.GetTypeInfo(typeof(global::Google.Protobuf.IBufferMessage)).IsAssignableFrom(typeof(T));
}
[global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
static T __Helper_DeserializeMessage<T>(grpc::DeserializationContext context, global::Google.Protobuf.MessageParser<T> parser) where T : global::Google.Protobuf.IMessage<T>
{
#if !GRPC_DISABLE_PROTOBUF_BUFFER_SERIALIZATION
if (__Helper_MessageCache<T>.IsBufferMessage)
{
return parser.ParseFrom(context.PayloadAsReadOnlySequence());
}
#endif
return parser.ParseFrom(context.PayloadAsNewBuffer());
}
[global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
static readonly grpc::Marshaller<global::GrpcService1.HelloRequest> __Marshaller_greet_HelloRequest = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::GrpcService1.HelloRequest.Parser));
[global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
static readonly grpc::Marshaller<global::GrpcService1.HelloReply> __Marshaller_greet_HelloReply = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::GrpcService1.HelloReply.Parser));
[global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
static readonly grpc::Marshaller<global::GrpcService1.Doc_Id> __Marshaller_greet_Doc_Id = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::GrpcService1.Doc_Id.Parser));
[global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
static readonly grpc::Marshaller<global::GrpcService1.Doc_result> __Marshaller_greet_Doc_result = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::GrpcService1.Doc_result.Parser));
[global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
static readonly grpc::Method<global::GrpcService1.HelloRequest, global::GrpcService1.HelloReply> __Method_SayHello = new grpc::Method<global::GrpcService1.HelloRequest, global::GrpcService1.HelloReply>(
grpc::MethodType.Unary,
__ServiceName,
"SayHello",
__Marshaller_greet_HelloRequest,
__Marshaller_greet_HelloReply);
[global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
static readonly grpc::Method<global::GrpcService1.Doc_Id, global::GrpcService1.Doc_result> __Method_GetDoc = new grpc::Method<global::GrpcService1.Doc_Id, global::GrpcService1.Doc_result>(
grpc::MethodType.Unary,
__ServiceName,
"GetDoc",
__Marshaller_greet_Doc_Id,
__Marshaller_greet_Doc_result);
/// <summary>Service descriptor</summary>
public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
{
get { return global::GrpcService1.GreetReflection.Descriptor.Services[0]; }
}
/// <summary>Base class for server-side implementations of Greeter</summary>
[grpc::BindServiceMethod(typeof(Greeter), "BindService")]
public abstract partial class GreeterBase
{
/// <summary>
/// Sends a greeting
/// </summary>
/// <param name="request">The request received from the client.</param>
/// <param name="context">The context of the server-side call handler being invoked.</param>
/// <returns>The response to send back to the client (wrapped by a task).</returns>
[global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
public virtual global::System.Threading.Tasks.Task<global::GrpcService1.HelloReply> SayHello(global::GrpcService1.HelloRequest request, grpc::ServerCallContext context)
{
throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, ""));
}
[global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
public virtual global::System.Threading.Tasks.Task<global::GrpcService1.Doc_result> GetDoc(global::GrpcService1.Doc_Id request, grpc::ServerCallContext context)
{
throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, ""));
}
}
/// <summary>Creates service definition that can be registered with a server</summary>
/// <param name="serviceImpl">An object implementing the server-side handling logic.</param>
[global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
public static grpc::ServerServiceDefinition BindService(GreeterBase serviceImpl)
{
return grpc::ServerServiceDefinition.CreateBuilder()
.AddMethod(__Method_SayHello, serviceImpl.SayHello)
.AddMethod(__Method_GetDoc, serviceImpl.GetDoc).Build();
}
/// <summary>Register service method with a service binder with or without implementation. Useful when customizing the service binding logic.
/// Note: this method is part of an experimental API that can change or be removed without any prior notice.</summary>
/// <param name="serviceBinder">Service methods will be bound by calling <c>AddMethod</c> on this object.</param>
/// <param name="serviceImpl">An object implementing the server-side handling logic.</param>
[global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
public static void BindService(grpc::ServiceBinderBase serviceBinder, GreeterBase serviceImpl)
{
serviceBinder.AddMethod(__Method_SayHello, serviceImpl == null ? null : new grpc::UnaryServerMethod<global::GrpcService1.HelloRequest, global::GrpcService1.HelloReply>(serviceImpl.SayHello));
serviceBinder.AddMethod(__Method_GetDoc, serviceImpl == null ? null : new grpc::UnaryServerMethod<global::GrpcService1.Doc_Id, global::GrpcService1.Doc_result>(serviceImpl.GetDoc));
}
}
}
#endregion
Hmm. looks like they use some custom tool-chain tools that we don’t support. I’ll have a look, but no promises; this might just be tied to needing MSBuild.
It’s already great that you’re watching.
I have tried under all languages in Water and Grpc.tools (which generates the classes) blocks.
In VS, the configuration is:
<PackageReference Include="Grpc.Tools" Version="2.40.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
The tricky part will be to find out what tool to run and how to run it, but more so, how to hook that discovery up in a more generic fashion that is, ideally, not hardcoded to this particular use case (Grpc) but applicable to any such similar tools.
start here
grpc / (version 2.48.1 today)
I did the test and it does come out with a class in “imbitable” c#
Thanx. i might just be bored enough today to hook this up explicitly (ie hardcoded Protobuffer support; not support for arbitrary custom MSBuild tasks).
One note before I forget later: for this to work (eventually) you’ll want to set the build action type for the file in your .elements to match VC#:
<Protobuf Include="Protos\greet.proto" />
/Users/mh/Downloads/Grpc/Water/TestGrpc/Protos/greet.proto: File does not reside within any path specified using --proto_path (or -I). You must specify a --proto_path which encompasses this file. Note that the proto_path must be an exact prefix of the .proto file names – protoc is too dumb to figure out when two paths (e.g. absolute and relative) are equivalent (it’s harder than you think).
LOL.
Starting compile for TestGrpc Echoes
RemObjects Elements Compiler for .NET, Cocoa, Java and Island.
Copyright 2003-2022 RemObjects Software, LLC. All rights reserved. Created by Carlo Kok
Version 11.0.0.2772 (develop) built on bajor, 20220912-174036. Commit 7194c80.
Source file: /Users/mh/Downloads/Grpc/Water/TestGrpc/Controllers/WeatherForecastController.pas
Source file: /Users/mh/Downloads/Grpc/Water/TestGrpc/Program.pas
Source file: /Users/mh/Downloads/Grpc/Water/TestGrpc/Startup.pas
Source file: /Users/mh/Downloads/Grpc/Water/TestGrpc/WeatherForecast.pas
Source file: /Users/mh/Library/Application Support/RemObjects Software/EBuild/Obj/TestGrpc-ED4E41A26237CF6705ADDF2B93CF1461DFEFA2C2/Debug/Echoes/ProtoBuffers/Greet.cs
oddly it only genertates one file; thje VC# one has Greet.cs and GreetGrpc.cs in its objc folder…
Done and in (pending actual testing/feedback). Unfortunately I cant get a new build to you until later tonight.
Wonderful.
As we don’t live on the same continent, late tonight is really not a problem, so I’ll try to wait
Thanks in advance
Norbert
Try if adding this .cs fine to your project manually makes it work; if so we should be good.
Greet.cs (42.3 KB)
Oddly, when i specify --grpc_out
as mention in the doc you linked earlier, and which I assume is supposed to generate the second file:
--grpc_out=/Users/mh/Library/Application Support/RemObjects Software/EBuild/Obj/TestGrpc-ED4E41A26237CF6705ADDF2B93CF1461DFEFA2C2/Debug/Echoes/ProtoBuffers
--plugin=/Users/mh/Library/Application Support/RemObjects Software/EBuild/Packages/NuGet/grpc.tools/2.48.0/tools/macosx_x64/grpc_csharp_plugin
it fails with
protoc-gen-grpc: program not found or is not executable
Please specify a program using absolute path or make sure the program is available in your PATH system variable
–grpc_out: protoc-gen-grpc: Plugin failed with status code 1.
Update nevermind, works: needs --plugin protoc-gen-grpc=/Users/mh/Library/Application Support/RemObjects Software/EBuild/Packages/NuGet/grpc.tools/2.48.0/tools/macosx_x64/grpc_csharp_plugin
However, I do get 4 errors with this generated code
-> Phase Resolving Bodies started.
E: Type mismatch, cannot assign "Grpc.Core.Marshaller<Google.Protobuf.IMessage>" to "Grpc.Core.Marshaller<HelloRequest>" [/Users/mh/Library/Application Support/RemObjects Software/EBuild/Obj/TestGrpc-ED4E41A26237CF6705ADDF2B93CF1461DFEFA2C2/Debug/Echoes/ProtoBuffers/GreetGrpc.cs (52)]
E: Type mismatch, cannot assign "Grpc.Core.Marshaller<Google.Protobuf.IMessage>" to "Grpc.Core.Marshaller<HelloReply>" [/Users/mh/Library/Application Support/RemObjects Software/EBuild/Obj/TestGrpc-ED4E41A26237CF6705ADDF2B93CF1461DFEFA2C2/Debug/Echoes/ProtoBuffers/GreetGrpc.cs (54)]
E: Type mismatch, cannot assign "Grpc.Core.Marshaller<Google.Protobuf.IMessage>" to "Grpc.Core.Marshaller<Doc_Id>" [/Users/mh/Library/Application Support/RemObjects Software/EBuild/Obj/TestGrpc-ED4E41A26237CF6705ADDF2B93CF1461DFEFA2C2/Debug/Echoes/ProtoBuffers/GreetGrpc.cs (56)]
E: Type mismatch, cannot assign "Grpc.Core.Marshaller<Google.Protobuf.IMessage>" to "Grpc.Core.Marshaller<Doc_result>" [/Users/mh/Library/Application Support/RemObjects Software/EBuild/Obj/TestGrpc-ED4E41A26237CF6705ADDF2B93CF1461DFEFA2C2/Debug/Echoes/ProtoBuffers/GreetGrpc.cs (58)]
<- Phase Resolving Bodies finished, took 3.974s.
GreetGrpc.cs (13.5 KB)