Giter Site home page Giter Site logo

protobuf-net.grpc's Introduction

protobuf-net logo protobuf-net.Grpc

Build status

protobuf-net.Grpc adds code-first support for services over gRPC using either the native Grpc.Core API, or the fully-managed Grpc.Net.Client / Grpc.AspNetCore.Server API.

It should work on all .NET languages that can generate something even remotely like a regular .NET type model.

Usage is as simple as declaring an interface for your service-contract:

[ServiceContract]
public interface IMyAmazingService {
    ValueTask<SearchResponse> SearchAsync(SearchRequest request);
    // ...
}

then either implementing that interface for a server:

public class MyServer : IMyAmazingService {
    // ...
}

or asking the system for a client:

var client = http.CreateGrpcService<IMyAmazingService>();
var results = await client.SearchAsync(request);

This would be equivalent to the service in .proto:

service MyAmazingService {
    rpc Search (SearchRequest) returns (SearchResponse) {}
	// ...
}

Obviously you need to tell it the uri etc - see Getting Started. Usually the configuration is convention-based, but if you prefer: there are various configuration options.

Getting hold of it

Everything is available as pre-built packages on nuget; in particular, you probably want one of:

Usage examples are available in C#, VB and F#.

Anything else?

protobuf-net.Grpc is created and maintained by Marc Gravell (@marcgravell), the author of protobuf-net.

It makes use of tools from grpc, but is not official associated with, affiliated with, or endorsed by that project.

I look forward to your feedback, and if this could save you a ton of time, you're always welcome to Buy me a coffee

protobuf-net.grpc's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

protobuf-net.grpc's Issues

CallContextAccessor

In my current approach I have a bunch of microservices each of which I have an ExecutionContextAccessor which is registered as InstancePerLifetimeScope within Autofac.

The HttpContextAccessor as well as Finbuckle's MultiTenantContextAccessor are injected into my ExecutionContextAccesor's constructor.

Would it be possible to inject the CallContext into my ExecutionContextAccessor in a similar manner, is that possible?

This becomes quite important for trace-ability of gRPC-type inter-service communications where Saga flows call across service boundaries.

Thanks in advance!

Add support for an inherited interfaces

I tried to realize IAddUser<T> interface for variety of methods which are described realization of the same connected classes like AddLogistian: IAddLogistian, IAddLogistian : IAddUser<Logistian> and so on.
For example:

public interface IAddUser<T> where T: User
{
    Task<ServiceObject> Add(AddUserRequest addUserRequest);
}

public interface IAddLogistian : IAddUser<Logistian> { }

public class AddLogistian : IAddLogistian
{
      public async Task<ServiceObject> Add(AddUserRequest addUserRequest)
      {
          ...
      }
}

But the ServiceContract attribute which is used on IAddLogistian, gives a execution error: "Specified method is not supported."

StackTrace:
at ProtoBuf.Grpc.Internal.Proxies.LiteClientBase.IAddLogistian_Proxy_0.IAddUser`1.Add(AddUserRequest )
at WebFoundationClassesCore.Services.DatabaseServices.AddUserServices.Service.AddLogistian.d__1.MoveNext() in C:\Users\Rebelion\repos\WebFoundationClassesCore\WebFoundationClassesCore\Services\DatabaseServices\AddUserServices\Service\AddLogistian.cs:line 44

Source: ProtoBuf.Grpc.Internal.Proxies

So, there are 2 questions:

  1. How is it possible realize the described above shema?
  2. Is it possible to use IAddUser<T> for different services without underlying service like IAddLogistian (in the future - nowaday the shema with IAddLogistian : IAddUser<Logistian> isn't work)?

Thank you.

Custom bindings for inherited DTO

Hello, Mark.

I don't know is this a question on your side or on dotnet-grpc team, but...
Is it possible to add any custom bindings or other ways to bind inherited DTO?
So, here an example.

public interface IAddUser
{
      Task<ServiceObject> Add(AddUserRequest request);
}

[ServiceContract]
public interface IAddLogistian
{
      Task<ServiceObject> Add(AddUserRequest);
}

[ProtoContract]
public class AddUserRequest
{
      [ProtoMember(1)]
      public string Fullname { get; set; }
}

public class AddLogistianRequest : AddUserRequest
{
     [ProtoMember(2)]
     public string Number { get; set; }
}

So, when I try to call remote Add method, I see, that I have only one field in the received DTO, not 2. But json serialized DTO on the caller side contains 2 members.

So, is it any way to signalize romete side to use inherited DTO or not?

Tnak you.

protobuf-net inheritance incompatible with Google's Protoc types

Hi Marc,

I tried to send a new Pull Request but as my previous PR hasn't been merged yet, my new PR was added to the previous one instead of creating a new one.

Anyway the relevant commit is:

25ee825

Where I've added tests to test protobuf-net inheritence and compatibility with Google's protoc and grpc code-gen for C#.

There's a few issues, tested with these models:

[ProtoContract]
[ProtoInclude(10, typeof(Sub))]
[ProtoInclude(11, typeof(GenericBase<>))]
public abstract class Base
{
    [ProtoMember(1)]
    public string String { get; set; }
    [ProtoMember(2)]
    public Dictionary<string,string> StringDictionary { get; set; }
}

[ProtoContract]
public class Sub : Base
{
    [ProtoMember(1)]
    public long Long { get; set; }
}

[ProtoContract]
public class Poco
{
    [ProtoMember(1)]
    public short Short { get; set; }
}

[ProtoContract]
[ProtoInclude(20, typeof(SubGeneric))]
public class GenericBase<T> : Base
{
    [ProtoMember(1)]
    public T Result { get; set; }
}

[ProtoContract]
public class SubGeneric : GenericBase<Poco>
{
    [ProtoMember(1)]
    public int Int { get; set; }
}

The basic inheritance test works where you can Serialize/Deserialize the simple Sub example in protobuf-net, but it partially fails when trying to deserialize the SubGeneric Type where it fails to deserialize the Base Types properties:

var from = new SubGeneric { 
    Int = 1, 
    String = "Base", 
    StringDictionary = new Dictionary<string, string> {
        {"A", "OK"}
    },
    Result = new Poco {
        Short = 2
    }
};

using var ms = new MemoryStream();
Serializer.Serialize(ms, from);
ms.Position = 0;
var to = Serializer.Deserialize<SubGeneric>(ms);

Assert.Equal(from.Result.Short, to.Result.Short);
Assert.Equal(from.Int, to.Int);
Assert.Equal(from.String, to.String); //FAIL to.String == null
Assert.Equal(from.StringDictionary["A"], to.StringDictionary["A"]); //FAIL to.StringDictionary == null

Protoc Inheritance Incompatibility

I've then taken the .proto generated from typeModel.GetSchema() schema to generate the protoc models using Google's protoc and grpc tools which whilst it generates all types does not provide anyway AFAICS to populate the base properties:

[Fact]
public void CanDeserializeInheritedTypesWithProtoc()
{
    var from = new Sub {
        Long = 1,
        // Cannot populate inherited properties: 
        // String = "Base", 
        // StringDictionary = new Dictionary<string, string> {
        //     {"A", "OK"}
        // }
    };

    using var ms = new MemoryStream();
    from.WriteTo(ms);
    ms.Position = 0;

    var to = Sub.Parser.ParseFrom(ms);

    Assert.Equal(from.Long, to.Long);
}

From the inheritence.proto we can see that the Base type has the container for all the sub types that inherits it, but I don't see how that's meant to work with gRPC in practice? as when you define a Service that sends a Sub or SubGeneric it only generates an API that lets you pass an instance of Sub in, not the Base type which contains all the Sub Type info:

rpc GetSub(Sub) returns (Sub) {}

Otherwise the test from protoc Sub -> protoc Sub is able to serialize its direct property, however it doesn't work when trying to deserialize protoc Sub -> protobuf.net Sub:

[Fact]
public void CanDeserializeProtocInheritedTypesWithProtobufNet()
{
    var from = new Sub { 
        Long = 1,
        // Cannot populate inherited properties: 
        // String = "Base", 
        // StringDictionary = new Dictionary<string, string> {
        //     {"A", "OK"}
        // }
    };
    
    using var ms = new MemoryStream();
    from.WriteTo(ms);
    ms.Position = 0;
    //throws System.InvalidOperationException : It was not possible to prepare a serializer for: ProtobufNet.Grpc.Test.Integration.Base
    var to = Serializer.Deserialize<Integration.Sub>(ms); 
    
    Assert.Equal(from.Long, to.Long);
}

I'm assuming this scenario is meant to be compatible as it's required for protobuf-net.Grpc to work with protoc generated clients, but I'm not seeing where I'm doing inheritance wrong as from all relevant docs the Sub types are meant to be annotated on the Base type but this doesn't look like it translates well in protoc generated clients.

[Feature request] Allow interface inheritance to extend service

Would it be possible to have [ServiceContract] interface inherit another generic interface in order to reduce code duplication for simple CRUD services and allow generic reusage in components? Based on this example:

    [ServiceContract(Name = "MyApp.TestDataService")]
    public interface ITestDataService : IDataService<TestDto>
    {

    }

    public interface IDataService<TDto> where TDto : class, new()
    {
        ValueTask<List<TDto>> GetAllAsync(CallContext context = default);
        ValueTask<TDto> GetByIdAsync(IdMessage message, CallContext context = default);
        ValueTask<TDto> AddAsync(TDto dto, CallContext context = default);
        ValueTask<TDto> UpdateAsync(TDto dto, CallContext context = default);
        ValueTask DeleteAsync(TDto dto, CallContext context = default);
    }

    [ProtoContract]
    public class TestDto
    {
        [ProtoMember(1)]
        public int Id { get; set; }

        [ProtoMember(2)]
        public string Name { get; set; }
    }

    [ProtoContract]
    public class IdMessage
    {
        [ProtoMember(1)]
        public int Id { get; set; }
    }

If interface that service marked with [ServiceContract] inherits (in this case IDataService) does not implement [ServiceContract] then it's methods could be incorporated into outmost service (ITestDataService) with it's address (in this case MyApp.TestDataService). Alternatively introduce new attribute, something like [ServiceContractExtension] which would allow this functionality without breaking the way it works at the moment. Currently those methods would raise NotSupportedException since IDataService is not marked with [ServiceContract].

MarshallerFactory access modifier problem

Hello, Marc.

Is it possible to remove "internal" access modified from CreateMarshaller. I try to realize my own class like GRPCClientPOCO, which uses alternative approach. But it's really not possible to create derived class which can override CreateMarshaller. Could you remove this modificator?
Thnxs.

Question - Future of library and contributions

I see this library as where the new .netcore 3.0 stuff should have gone... or at least supporting service/operation contracts, and have the ability to auto generate protos.

I'm curious what the plans are with your library... is this more of a research effort, or do you anticipate it getting to a place where its consumed in production code bases (not trying to imply anything about current quality or feature set).

Also, what is your take on contributions? If I was going to deploy into production, I see the things I'd probably want figured out:

  1. some way of providing a type conversion/mapping for not wellknown types
  2. Authentication/Authorization (probably same/similar implementation to whats in dotnetcore managed grpc (https://docs.microsoft.com/en-us/aspnet/core/grpc/authn-and-authz?view=aspnetcore-3.1)

I was wondering if you were interested in help, or proposals on helping out with these items.

AddGrpcClient / CreateGrpcService lifetime

A couple of questions if that's okay:

  • Is there an equivalent of AddGrpcClient that works with this library?
  • Is the result of CreateGrpcService designed to be long-lived? e.g. inject a HttpClient into a singleton service, call CreateGrpcService on it once, and use this for the lifetime of the ASP.NET app. Is this safe?

Allow OperationContract with multiple arguments

I'm trying to evaluate a replacement of WCF with gRPC, within a big code base with interfaces as "code first" approach. So your work here is very highly appreciated !

So far, I've had decent results, but aside from #27, the biggest challenge for using the exact same interfaces is that we often have operations that have multiple arguments. I can see a number of workarounds, but I was wondering whether it could make sense to handle this case inside protobuf-net.Grpc, basically stuffing all arguments (except a last CallContext) in a Tuple (or Tuple-like). I'll try to give it a shot, but would be interested in your thoughts about it.

[Question] protobuf-net.Grpc vs WCF performance

Hi,

I've created a test client-server based on your sample code like:

Server

    public class MyService : IMyService
    {
        private static int _counter = 0;

        public MyResponse Test2(MyRequest request)
        {
            _counter++;

            return new MyResponse { Name = $"{request?.Name} {_counter}", 
                                                      Number = request.Number };
        }
    }

Client

            GrpcClientFactory.AllowUnencryptedHttp2 = true;

            using (var channel = GrpcChannel.ForAddress("http://localhost:5001"))
            {
                var service = channel.CreateGrpcService<IMyService>();

                try
                {
                    var t = new Stopwatch();
                    t.Start();

                    const int count = 1000;

                    for (int i = 0; i < count; i++)
                    {
                        var result = service.Test2(new MyRequest { 
                                                  Name = "phil", Number = i });
                    }

                    Console.WriteLine(t.Elapsed.TotalSeconds/count);
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
            }

And a similar test using WCF.

The gRPC app takes 20ms per iteration, but WCF takes 5ms. Am I missing something? I expected it to be the other way round.

Problem with resolve service instance in the base class (possible)

Hello.

I have a strange behavior of my code.

Let's descripe the situation.
I have 3 microservices which describe GoogleMaps Request-Response services.

I created base generic class

    public class GRPCServiceLayer<T> where T:class
    {
        private readonly HttpClient httpClient;
        private readonly ClientFactory clientFactory;
        private readonly ResultObjectCreator resultObjectCreator;
        private readonly ErrorObjectCreator errorObjectCreator;
        private readonly string connectionAddress;

        protected T service;

        public GRPCServiceLayer(string connectionAddress, ClientFactory clientFactory, ResultObjectCreator resultObjectCreator, ErrorObjectCreator errorObjectCreator)
        {
            httpClient = new HttpClient { BaseAddress = new Uri(connectionAddress), DefaultRequestVersion = new Version(2,0) };
            service = httpClient.CreateGrpcService<T>(clientFactory: clientFactory);

            this.resultObjectCreator = resultObjectCreator;
            this.errorObjectCreator = errorObjectCreator;
            this.clientFactory = clientFactory;
            this.connectionAddress = connectionAddress;
        }

        public ServiceObject TransformResponse<TFrom, TTo>(ServiceObject rawResponse) where TFrom : class
                                                                                      where TTo : class
        {
            ServiceObject response;

            if (rawResponse.IsValid && rawResponse.IsValuable)
            {
                var googleDirectionsResponse = JsonConvert.DeserializeObject<TFrom>(rawResponse.Result.ToString());
                var directionResponse = Mapper.Map<TTo>(googleDirectionsResponse);

                response = resultObjectCreator.Create(result: directionResponse);
            }
            else { response = rawResponse; }

            return response;
        }

here ResultObjectCreator and ErrorObjectCreator are the classes with method Create both return an ServiceObject class object which is a pure Data object with no behavior inside (just fields, no methods).

I derived a class from GRPCServiceLayer:

    [Singleton(typeof(IDirection))]
    public class GoogleMapsDirection : GRPCServiceLayer<IDirection>, IDirection
    {
        private readonly ServerAddressConfig serverAddressConfig;

        public GoogleMapsDirection(ErrorObjectCreator errorObjectCreator, 
                                   ResultObjectCreator resultObjectCreator,
                                   IOptions<ServerAddressConfig> serverAddressConfig,
                                   ClientFactory clientFactory) : base(serverAddressConfig.Value.GeolocationServer, clientFactory, resultObjectCreator, errorObjectCreator)
        {
            HttpClientExtensions.AllowUnencryptedHttp2 = true;
        }

        public async Task<ServiceObject> GetDirection(BaseDirectionRequest request)
        {
            var rawResponse = await service.GetDirection(request);//.ConfigureAwait(false);
            var response = TransformResponse<DirectionsResponse, BaseDirectionResponse>(rawResponse);

            return response;
        }
    }

and each time I tried to execute GetDirection I have an error like this:

An error occurred while sending the request.
(InnerException - The response ended prematurely.)

with StackTrace

at System.Net.Http.HttpConnection.<SendAsyncCore>d__53.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
   at System.Net.Http.HttpConnectionPool.<SendWithNtConnectionAuthAsync>d__48.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
   at System.Net.Http.HttpConnectionPool.<SendWithRetryAsync>d__47.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
   at System.Net.Http.RedirectHandler.<SendAsync>d__4.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
   at System.Net.Http.DiagnosticsHandler.<SendAsync>d__2.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
   at System.Net.Http.HttpClient.<FinishSendAsyncUnbuffered>d__71.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
   at Grpc.Net.Client.Internal.GrpcCall`2.<SendAsync>d__73.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter.GetResult()
   at Grpc.Net.Client.Internal.GrpcCall`2.<GetResponseAsync>d__66.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at ProtoBuf.Grpc.Internal.Reshape.<UnaryTaskAsyncImpl>d__10`2.MoveNext() in c:\Code\protobuf-net.Grpc\src\protobuf-net.Grpc\Internal\Reshape.cs:line 225
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at WebFoundationClassesCore.Services.MapServices.DirectionService.GoogleMapsDirection.<GetDirection>d__2.MoveNext() in C:\Users\Rebelion\repos\WebFoundationClassesCore\WebFoundationClassesCore\Services\MapServices\DirectionService\Service\GoogleMapsDirection.cs:line 52

(Inner Stacktrace:

   at System.Net.Http.HttpConnection.<FillAsync>d__87.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter.GetResult()
   at System.Net.Http.HttpConnection.<ReadNextResponseHeaderLineAsync>d__84.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task)
   at System.Threading.Tasks.ValueTask`1.get_Result()
   at System.Runtime.CompilerServices.ConfiguredValueTaskAwaitable`1.ConfiguredValueTaskAwaiter.GetResult()
   at System.Net.Http.HttpConnection.<SendAsyncCore>d__53.MoveNext()

But code like this works fine!

public class GRPCServiceLayer<T>  where T:class
{
    //private readonly HttpClient httpClient;
    //private readonly ClientFactory clientFactory;
    private readonly ResultObjectCreator resultObjectCreator;
    private readonly ErrorObjectCreator errorObjectCreator;
    private readonly string connectionAddress;

    protected T service;

    public GRPCServiceLayer(string connectionAddress, ClientFactory clientFactory, ResultObjectCreator resultObjectCreator, ErrorObjectCreator errorObjectCreator)
    {
        //httpClient = new HttpClient { BaseAddress = new Uri(connectionAddress), DefaultRequestVersion = new Version(2,0) };
        //service = httpClient.CreateGrpcService<T>(clientFactory: clientFactory);

        this.resultObjectCreator = resultObjectCreator;
        this.errorObjectCreator = errorObjectCreator;
        //this.clientFactory = clientFactory;
        this.connectionAddress = connectionAddress;
    }

    public ServiceObject TransformResponse<TFrom, TTo>(ServiceObject rawResponse) where TFrom : class
                                                                                  where TTo : class
    {
        ServiceObject response;

        if (rawResponse.IsValid && rawResponse.IsValuable)
        {
            var googleDirectionsResponse = JsonConvert.DeserializeObject<TFrom>(rawResponse.Result.ToString());
            var directionResponse = Mapper.Map<TTo>(googleDirectionsResponse);

            response = resultObjectCreator.Create(result: directionResponse);
        }
        else { response = rawResponse; }

        return response;
    }
    [Singleton(typeof(IDirection))]
    public class GoogleMapsDirection : GRPCServiceLayer<IDirection>, IDirection
    {
        private readonly ServerAddressConfig serverAddressConfig;
        private readonly HttpClient httpClient1;
        private readonly IDirection Service1;

        public GoogleMapsDirection(ErrorObjectCreator errorObjectCreator, 
                                   ResultObjectCreator resultObjectCreator,
                                   IOptions<ServerAddressConfig> serverAddressConfig,
                                   ClientFactory clientFactory) : base(serverAddressConfig.Value.GeolocationServer, clientFactory, resultObjectCreator, errorObjectCreator)
        {
            HttpClientExtensions.AllowUnencryptedHttp2 = true;

            httpClient1 = new HttpClient { BaseAddress = new Uri(serverAddressConfig.Value.GeolocationServer), DefaultRequestVersion = new Version(2, 0) };
            Service1 = httpClient1.CreateGrpcService<IDirection>(clientFactory: clientFactory);
        }

        public async Task<ServiceObject> GetDirection(BaseDirectionRequest request)
        {
            var rawResponse = await Service1.GetDirection(request);
            var response = TransformResponse<DirectionsResponse, BaseDirectionResponse>(rawResponse);

            return response;
        }
    }

I cannot recognize why definition and resolving service in base constructor instead of derived constructor brokes my code? Is this a same limitation of protobuf.grpc package or my curved hands?

Thank you.

Use struct as parameters and return value.

I am trying to create simple method with int parameter and it fails with System.Security.VerificationException: 'Method ProtoBuf.Grpc.Configuration.ServerBinder.AddMethod: type argument 'System.Int32' violates the constraint of type parameter 'TRequest'.' is it expected behavior? Should I wrap it to some request class? Are there any limitations to use struct as parameters? Will it be allowed in the future?

streaming an IObservable

using grpc with a proto file as per asp.net docs i wrote

service Dispatcher {

	rpc RequestEvent (Request) returns (stream Event) {}

the grpc tools generate the service which I then integrate to the existing observables in my system like

 internal class DispatcherImpl : Dispatcher.Dispatcher.DispatcherBase{
        
        public override async Task RequestEvent(Request request, IServerStreamWriter<Event> responseStream, ServerCallContext context){
  
                
                await SomeController.Observable
                    .ForEachAsync(value =>
                        {
                            responseStream.WriteAsync(value).Wait();
                        }, 
                        context.CancellationToken);


        }

this pretty much works ok, but I would like to send .net types and share them and avoid the build hack so I came here. However all your samples use the IAsyncEnumerable, although you mentioned that Task is also possible. So, can you provide an example based on your TimeService perhaps that streams an IObservable?

No serializer defined for type: 'System.Object'

Hi,

I'm having an issue trying to use protobuf-net.Grpc.Native. I'm finding that parameters from calls from the gRPC client are not being serialized for custom types. I have an example repo which demonstrates the issue. When I try and call the GetUsers method the QueryRequest object is not being serialized.

No serializer defined for type: 'System.Object' DAL/Shared/Client.cs (Line 21)

Any help/pointers would be appreciated.

Thanks.

[Feature Request] Provide an alternative custom attribute to System.ServiceModel.ServiceContract to remove dependency with System.ServiceModel.dll

Pretty much as the title says.
While trying to test this library from Unity3D engine, I had some problems importing the System.ServiceModel.dll which led me to inspect your code and noticed the attribute is matched by name.
Knowing this I implemented my own System.ServiceModel.ServiceContractAttribute class to fool the library and it worked.
As I understand there's no other part of the library or its dependencies that depend on System.ServiceModel.dll so providing a second equivalent attribute (ProtoServiceContractAttribute?) in addition to the current MS one, some users will be able to remove the otherwise unneeded dll.

This is somewhat related to #62 as enabling the inheritance flag in the alternative attribute could solve their problems I think.

Is support for the [Authorize] attribute on the method level possible?

I was playing around with the code first approach, really like that over .proto files :)

But I ran into an issue with authorization when adding the [Authorize] attribute to a method in the service implementation. It would simply skip it. It works as expected if you add it on the class level.

It seems that on

metadata.AddRange(stub.Method.GetCustomAttributes(inherit: true));
it uses the interface member to find custom attributes as opposed to the way it does in on the service type where it's the implementation that is used.

I made it work by adding this, finding attributes for the implemented method also

var implementedMethod = typeof(TService).GetMethod(stub.Method.Name, stub.Method.GetParameters()
    .Select(s => s.ParameterType)
    .ToArray());

if (implementedMethod != null) metadata.AddRange(implementedMethod.GetCustomAttributes(inherit: true));

but I'm pretty sure that's a very quick and naive way to fix it 😋 and there is certainly a more robust way to support it.

I was not able to find another way in the TryBind method to access the actual MethodInfo of the implemented type.

CreateGrpcService throws FileLoadException

I get this error when I call the HttpClient.CreateGrpcService method:

{System.TypeInitializationException: The type initializer for 'DefaultProxyCache`3' threw an exception. ---> System.IO.FileLoadException: Could not load file or assembly 'System.Reflection.Emit.ILGeneration, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. The located assembly's manifest definition does not match the assembly reference. (0x80131040)
File name: 'System.Reflection.Emit.ILGeneration, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
   at ProtoBuf.Grpc.Internal.ProxyEmitter.CreateFactory[TChannel,TService](Type baseType, BinderConfiguration binderConfig)
   at ProtoBuf.Grpc.Configuration.ClientFactory.DefaultProxyCache`3..cctor() in C:\Code\protobuf-net.Grpc\src\protobuf-net.Grpc\Configuration\ClientFactory.cs:line 59

I added the protobuf-net.Grpc and protobuf-net.Grpc.HttpClient packages (both version 0.0.3-alpha54) so I don't think any assemblies are missing? Let me know if you need more details.

This is in a .NET Core 3.0 application.

EDIT: The following standalone code seems to reproduce it:

using ProtoBuf.Grpc;
using ProtoBuf.Grpc.Client;
using System;
using System.Net.Http;
using System.ServiceModel;
using System.Threading.Tasks;

namespace GrpcClientTest
{
    [ServiceContract]
    public interface ITestService
    {
        Task<string> TestAsync(string request, CallContext context = default);
    }

    class Program
    {
        static void Main(string[] args)
        {
            var http = new HttpClient();
            var client = http.CreateGrpcService<ITestService>(); // Exception

        }
    }
}

As a .NET Core 3.0 (Preview 6) Console App, with the following packages installed:

  • protobuf-net.Grpc (0.0.3-alpha.54)
  • protobuf-net.Grpc.HttpClient (0.0.3-alpha.54)

Question - protobuf-net.Grpc.Native and protobuf-net.Grpc for server and client

Hi Marc, thanks for this great project. This is exactly what I was hoping how grpc is implemented in C#
Would like to know if possible to use protobuf-net.Grpc.Native for server to run on dotnet4.7.2, and the dotnet core 3.1 version for client (protobuf-net.Grpc, Grpc.Net,Client)?

Are they compatible? And if yes, would it be supported for the long run? Any limitations?

Document IGrpcService

I've been exploring the code and I'm wondering how IGrpcService works.

It seems like it's an alternative to having to use [ServiceContract], i.e. rather than:

[ServiceContract]
public interface IMyService
{
    int SomeMethod();
}

public class MyService : IMyService
{
    public int SomeMethod() => 1;
}

I can just do:

public class MyService : IGrpcService
{
    public int SomeMethod() => 1;
}

But I'm wondering how that works from the client side. Can I just do channel.CreateGrpcService<MyService>(), e.g. using the concrete type and not the interface?

That's quite nice in that you don't need to define an interface too, but doesn't this falls apart when you don't want your consumer project referencing the server project? You'd want them both referencing a separate project with just the contract stuff, e.g. request/response classes and an interface for the service, so no implementation.

Unless there's another use case I'm missing, perhaps where the contract is defined as an abstract type, inherits IGrpcService and is implemented in the server project?

ASP.NET core 3.1 gRPC-Web 2.27-pre1

Hello ,

I'm trying to get the experimental ASP.NET core 3.1 gRPC-Web 2.27-pre1 to work with code-first protobuf-net.Grpc core.

Is it supposed to function together or i'm i doing sometng wrong ?

   public void ConfigureServices(IServiceCollection services)
    {
        services.AddCodeFirstGrpc(config => {
        });
        services.AddCors(options => {
            options.AddPolicy(myCORs,
            builder => {
            builder.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod();
            });
        });                                   
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {         
        app.UseRouting()
            .UseGrpcWeb()
            .UseCors(myCORs)           
        .UseEndpoints(endpoints =>
        {
            GrpcEndpointRouteBuilderExtensions.MapGrpcService<DataService>(endpoints).EnableGrpcWeb();

info: ProtoBuf.Grpc.Server.ServicesExtensions.CodeFirstServiceMethodProvider[0]
RPC services being provided by AdminTransportGrpcService.DataService: 1
info: Microsoft.Hosting.Lifetime[0]
Now listening on: https://localhost:5001
info: Microsoft.Hosting.Lifetime[0]
Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
Content root path: C:\Users\Gustav Trede\stuff\code\AdminTransportServer_NET\AdminTransportGrpcService
info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
Request starting HTTP/2 OPTIONS https://localhost:5001/AdminTransportGrpcService.DataService/getAllData
info: Microsoft.AspNetCore.Cors.Infrastructure.CorsService[4]
CORS policy execution successful.
info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
Request finished in 37.7098ms 204
info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
Request starting HTTP/2 POST https://localhost:5001/AdminTransportGrpcService.DataService/getAllData application/grpc-web+proto 5
info: Microsoft.AspNetCore.Cors.Infrastructure.CorsService[4]
CORS policy execution successful.
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0]
Executing endpoint 'gRPC - /AdminTransportGrpcService.DataService/getAllData'
fail: Grpc.AspNetCore.Server.ServerCallHandler[6]
Error when executing service method 'getAllData'.
System.InvalidOperationException: A suitable constructor for type 'AdminTransportGrpcService.DataService' could not be located. Ensure the type is concrete and services are registered for all parameters of a public constructor.
at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.FindApplicableConstructor(Type instanceType, Type[] argumentTypes, ConstructorInfo& matchingConstructor, Nullable1[]& parameterMap) at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.CreateFactory(Type instanceType, Type[] argumentTypes) at Grpc.AspNetCore.Server.Internal.DefaultGrpcServiceActivator1.<>c.<.cctor>b__4_0()
at System.Lazy1.ViaFactory(LazyThreadSafetyMode mode) at System.Lazy1.ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor)
at System.Lazy1.CreateValue() at System.Lazy1.get_Value()
at Grpc.AspNetCore.Server.Internal.DefaultGrpcServiceActivator1.Create(IServiceProvider serviceProvider) at Grpc.AspNetCore.Server.Internal.CallHandlers.UnaryServerCallHandler3.HandleCallAsyncCore(HttpContext httpContext, HttpContextServerCallContext serverCallContext)
at Grpc.AspNetCore.Server.Internal.CallHandlers.UnaryServerCallHandler3.HandleCallAsyncCore(HttpContext httpContext, HttpContextServerCallContext serverCallContext) at Grpc.AspNetCore.Server.Internal.CallHandlers.ServerCallHandlerBase3.g__AwaitHandleCall|17_0(HttpContextServerCallContext serverCallContext, Method`2 method, Task handleCall)
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1]
Executed endpoint 'gRPC - /AdminTransportGrpcService.DataService/getAllData'
info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
Request finished in 178.9004ms 200 application/grpc-web

Example of how to setup encrypted channel?

I'm trying to setup encrypted communication between client and server using protobuf-net.Grpc.AspNetCore. I've setup Kestrel to use a certificate and require a client certificate as shown here. On the client I have setup the HttpClient to use a client certificate as shown here. When I run the Server and then the TestClient in my example repo I receive the following stack trace:

System.AggregateException
HResult=0x80131500
Message=One or more errors occurred. (Status(StatusCode=Internal, Detail="Error starting gRPC call: An error occurred while sending the request."))
Source=System.Private.CoreLib
StackTrace:
at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification)
at System.Threading.Tasks.Task`1.get_Result()
at DAL.TestClient.Program.Main(String[] args) in DAL\TestClient\Program.cs:line 10

This exception was originally thrown at this call stack:
    System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
    System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task)
    System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task)
    System.Runtime.CompilerServices.TaskAwaiter<TResult>.GetResult()
    ProtoBuf.Grpc.Internal.Reshape.UnaryTaskAsyncImpl<TRequest, TResponse>(Grpc.Core.AsyncUnaryCall<TResponse>, ProtoBuf.Grpc.Internal.MetadataContext) in Reshape.cs
    System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
    System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task)
    System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task)
    System.Threading.Tasks.ValueTask<TResult>.Result.get()
    System.Runtime.CompilerServices.ValueTaskAwaiter<TResult>.GetResult()
    ...
    [Call Stack Truncated]
Inner Exception 1:
RpcException: Status(StatusCode=Internal, Detail="Error starting gRPC call: An error occurred while sending the request.")

Would be grateful if someone could provide an example of how to setup encrypted channel.

Thanks!

Recognize well-known types

for APIs that involve, say, DateTime (rather than custom message types) we should try to pick the most reasonable looking well-known-type and use that;

obvious candidates:

  • DateTime / .google.protobuf.Timestamp (corelogic readily available in protobuf-net; BclHelpers.ReadTimeStamp / WriteTimestamp)
  • TimeSpan / .google.protobuf.Duration (core logic readily available in protobuf-net; BclHelpers.ReadDuration / WriteDuration)
  • void / .google.protobuf.Empty (already handled, but should migrate to the new Empty in protobuf-net)

the following probably already work fine (not sure about byte[]), as "assume a message with a single field with index 1" is the default behavior already:

  • double / .google.protobuf.DoubleValue (wrappers.proto)
  • float / .google.protobuf.FloatValue (wrappers.proto)
  • long / .google.protobuf.Int64Value (wrappers.proto)
  • ulong / .google.protobuf.UInt64Value (wrappers.proto)
  • int / .google.protobuf.Int32Value (wrappers.proto)
  • uint / .google.protobuf.UInt32Value (wrappers.proto)
  • bool / .google.protobuf.BoolValue (wrappers.proto)
  • string / .google.protobuf.StringValue (wrappers.proto)
  • byte[] / .google.protobuf.BytesValue (wrappers.proto)

Note: with the above, we should probably hard remove the ability to opt in/out of data-contract types on the marshaller; it should be "nope, it is either something we recognize, or a data-contract type".

Note: we should also think about null in the above; since outer-most message don't include a length prefix, this could be awkward - since wrappers.proto is proto3, that means that there is no way of expressing a difference between 0 and null. Maybe we just don't support nulls ?

less obvious - the only ones I can see us even considering are Type and Api

  • .google.protobuf.Any (any.proto) - mostly because I haven't seen this used to know the full intent
  • .google.protobuf.Api (api.proto) - possibly maps to Type when service-contract?
  • .google.protobuf.Type (type.proto) - possibly maps to Type when data-contract?
  • .google.protobuf.FieldMask (field_mask.proto) - very bespoke; not implemented
  • .google.protobuf.SourceContext (source_context.proto) - kinda like Assembly maybe?
  • .google.protobuf.Struct - think Dictionary<string, .google.protobuf.Value>
  • .google.protobuf.Value - a catch all for several other types; object maybe? or is that Any?

Integration with Serilog

I try to integrate protobuf-net.Grpc with Serilog so that all my logs are written as JSON

       Log.Logger = new LoggerConfiguration()
            .MinimumLevel.Debug()
            .MinimumLevel.Override("Microsoft", LogEventLevel.Information)
            .MinimumLevel.Override("Microsoft.AspNetCore", LogEventLevel.Warning)
            .MinimumLevel.Override("Grpc.AspNetCore", LogEventLevel.Warning)
            .Enrich.FromLogContext()
            .WriteTo.Console(new RenderedCompactJsonFormatter())
            .CreateLogger();

        await WebHost.CreateDefaultBuilder(args)
            .UseSerilog()
            .ConfigureKestrel(options =>
            {
                options.ListenLocalhost(Constants.GRPC_PORT, listenOptions =>
                {
                    listenOptions.Protocols = HttpProtocols.Http2;
                });
            })
            .UseStartup<StartupGrpc>()                
            .Build()
            .RunAsync();

When I start the service, I have the following logs:

{"@t":"2019-11-20T08:01:41.6062274Z","@m":"RPC services being provided by \"Service1.Service1\": 1","@i":"99042bdd","0":"Service1.Service1","1":1,"SourceContext":"ProtoBuf.Grpc.Server.ServicesExtensions.CodeFirstServiceMethodProvider"}
Hosting environment: Production
Content root path: xxx\Service1\bin\Debug\netcoreapp3.0
Now listening on: http://localhost:10001
Application started. Press Ctrl+C to shut down.
{"@t":"2019-11-20T08:01:42.4065927Z","@m":"Received Sum 12 + 12","@i":"a7280eb5","SourceContext":"Service1.Service1","RequestId":"0HLRDHVGJL7QN:00000001","RequestPath":"/Service1.Def.Service1/Sum","SpanId":"|6569d07-4421f5010ca3a214.1.1.31cbe944_","TraceId":"6569d07-4421f5010ca3a214","ParentId":"|6569d07-4421f5010ca3a214.1.1."}

As you can see there are some parts where Serilog is not used.

How can I change that behavior ?

Compatibility with blazor web assembly client

Hello, I actually migrate a silverlight/wcf app to blazor web assembly (.net core hosted)/grpc solution.

Your solution seem perfect for what i looking for (don't want to write the proto file but reuse class), but it seem you insist on the fact client and server project need target .net core 3 (in this doc https://protobuf-net.github.io/protobuf-net.Grpc/gettingstarted).

However my webAssembly webapp is in .net standard (2.1). Globally all my assembly target .net sandard except the server app.

There is a solution to make it work together anyway ?

thanks !

Make Callcontext injectable

Can I inject the Callcontext to the constructor of service implement?
Just like the IHttpContextAccssor that it does not need to be a method parameter.

NotSupported Exception

I am running within Docker Desktop with two services (Agg1 and Agg2) trying to execute a gRPC call between them.

When I attempt to invoke the service method I receive a NotSupported Exception.

Here is the Create Request class..

CreateRequest

Here is the ServiceContract for Agg1 ...
Agg1ServiceContract

Here is the code in Agg2 that throws the exception...
InvokeCreate

System.Exception:“Status(StatusCode=Unimplemented, Detail="")

Like in folder toys with PlayClient and PlayServer,if I Define a ServiceContract in PlayClient project like below:

[ServiceContract]
public interface IHello
{
       ValueTask<HelloResponse> SayHello(HelloRequest request);
}

and also Define the ServiceContract in the PlayServer.
In PlayServer i add the code like below :

server.Services.AddCodeFirst(new PlayServer.Hello());

In PlayClient i add the code like below:

var hello = channel.CreateGrpcService<IHello>();

and trying to invoke rpc request:

var result = await hello.SayHello(new HelloRequest { name = "1" });

and i got an error "System.Exception:“Status(StatusCode=Unimplemented, Detail="")"
it seems the IHello Interface ServiceContract must be the same on and in the same project and also referenced by the two project,PlayClient and PlayServer.

Will it designed to be so?what if i put the IHello Interface to the thirtpart people?

Question - Support methods with primitive parameters

Hi Marc, thanks for this great project. This is exactly what I was hoping how grpc is implemented in C#.

One question, is it possible to support methods w/ primitive parameters without defining DataContract or ProtoContract for those parameters? For example,

[ServiceContract(Name = "Hyper.Calculator")]
public interface ICalculator
{
double Multiply(double x, double y);
}

[Feature request] Server Reflection

gRPC Service reflection
https://github.com/grpc/grpc/blob/master/doc/server-reflection.md#grpc-server-reflection-protocol

I've started playing with gRPC server reflection, and think it would be a nice addition to also support gRPC server reflection with "code-first" services. This would allow e.g. .proto files to be generated, and services consumed easily by clients implemented in other languages.

Under the hoods, it's "just" another service (proto here). There's already implementations using Google.Protobuf (https://www.nuget.org/packages/Grpc.Reflection) and a library for integrating with ASP.NET Core (https://www.nuget.org/packages/Grpc.AspNetCore.Server.Reflection). Problem is that these libraries don't play along nice with protobuf-net.

I tried looking at how to implement this, but don't really know where to start. In protobuf-net, it's possible to get schema via RuntimeTypeModel. Can we somehow hook that up with Google.Protobuf's FileDescriptor? The reflection API is expected to return serialized file descriptors. (https://github.com/grpc/grpc/blob/master/src/proto/grpc/reflection/v1alpha/reflection.proto#L104)

So basically, my plan is:

  1. Get schema via RuntimeTypeModel
  2. Parse schema using protobuf-net.Reflection to get file descriptors

Am I overcomplicating?

CreateGrpcService errors on 4.7.2

After manually adding System.ServiceModel.Primitives nuget (to try and "manually" deal with PR #17) I get the below runtime error. Compiling and running with PR #17 causes the error to no longer occur (I suspect because some conditional compilation around .net standard 2.0 changed). Targetting 4.7.2 with 4.7.2 installed.

System.TypeInitializationException: The type initializer for 'DefaultProxyCache3' threw an exception. ---> System.NotSupportedException: The invoked member is not supported before the type is created.
at System.Reflection.Emit.TypeBuilder.GetField(String name, BindingFlags bindingAttr)
at ProtoBuf.Grpc.Internal.ProxyEmitter.CreateFactory[TChannel,TService](Type baseType, BinderConfiguration binderConfig) in C:\Code\protobuf-net.Grpc\src\protobuf-net.Grpc\Internal\ProxyEmitter.cs:line 253
at ProtoBuf.Grpc.Configuration.ClientFactory.DefaultProxyCache3..cctor() in C:\Code\protobuf-net.Grpc\src\protobuf-net.Grpc\Configuration\ClientFactory.cs:line 68 --- End of inner exception stack trace --- at ProtoBuf.Grpc.Configuration.ClientFactory.DefaultClientFactory.CreateClient[TBase,TService,TChannel](TChannel channel) in C:\Code\protobuf-net.Grpc\src\protobuf-net.Grpc\Configuration\ClientFactory.cs:line 76 at ProtoBuf.Grpc.Configuration.ClientFactory.CreateClient[TService](CallInvoker channel) in C:\Code\protobuf-net.Grpc\src\protobuf-net.Grpc\Configuration\ClientFactory.cs:line 31 at ProtoBuf.Grpc.Client.GrpcClientFactory.CreateGrpcService[TService](ChannelBase client, ClientFactory clientFactory) in C:\Code\protobuf-net.Grpc\src\protobuf-net.Grpc\Client\GrpcClientFactory.cs:line 29

Building with protobuf-net.grpc nuget package fails

Getting this error:
The type 'IAsyncEnumerable' exists in both 'System.Interactive.Async, Version=3.2.0.0, Culture=neutral, PublicKeyToken=94bc3704cddfc263' and 'System.Runtime, Version=4.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'

Had to use the workaround in create an alias for System.Interactive.Async.
Is there any way to avoid that?

Call AddGrpc in AddCodeFirstGrpc

AddCodeFirstGrpc only makes sense when AddGrpc is called so AddCodeFirstGrpc might as well do it. It will simplify your examples.

If you look at ASP.NET Core source code you will see that nested service registration is a common thing.

Bad gRPC response. Response did not have a content-type header

I use this library in my project. Earlier, I realized gRPC bridge for my microservices and everything worked fine. But after project was updated, each time I tried to use bridge, I got an error which is described in the question's header.

So, I changed code as you described in the new example - no affects.
I thought, that I had my hands curved and downloaded new code example from github and ran it (compiled Server, Client, and Shared independently by adding links they needed from nuget) - the same error was caught.

Could you check the reason of this error? (((
During the project example test (pb-net-grpc), I installed all last libraries which were needed for compilation and execution).

See the Stack Trace:

System.InvalidOperationException
HResult=0x80131509
Message = Bad gRPC response. Response did not have a content-type header.
Источник = Grpc.Net.Client
Stack trace:
at Grpc.Net.Client.Internal.GrpcCall2.ValidateHeaders() at Grpc.Net.Client.Internal.GrpcCall2.d__76.MoveNext()
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter.GetResult()
at Grpc.Net.Client.Internal.GrpcCall2.<GetResponseHeadersAsync>d__67.MoveNext() at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter1.GetResult()
at ProtoBuf.Grpc.Internal.Reshape.d__102.MoveNext() in C:\Code\protobuf-net.Grpc\src\protobuf-net.Grpc\Internal\Reshape.cs:line 222 at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Threading.Tasks.ValueTask1.get_Result()
at System.Runtime.CompilerServices.ValueTaskAwaiter`1.GetResult()
at Client_CS.Program.

d__0.MoveNext() in C:\Users\Rebelion\Downloads\protobuf-net.Grpc-master\protobuf-net.Grpc-master\examples\pb-net-grpc\Client_CS\Program.cs:line 20

Thank you.

protobuf-net.Grpc Emit support xamarin error

{System.TypeInitializationException: The type initializer for 'DefaultProxyCache`3' threw an exception. ---> System.TypeInitializationException: The type initializer for 'ProtoBuf.Grpc.Internal.ProxyEmitter' threw an exception. ---> System.PlatformNotSupportedException: Operation is not supported on this platform.
at System.Reflection.Emit.AssemblyBuilder.DefineDynamicAssembly (System.Reflection.AssemblyName name, System.Reflection.Emit.AssemblyBuilderAccess access) [0x00000] in /Library/Frameworks/Xamarin.iOS.framework/Versions/Current/src/Xamarin.iOS/mcs/class/corlib/System.Reflection.Emit/AssemblyBuilder.pns.cs:129

[Question] Does hosting GRPC services automatically preclude also hosting rest

I've got an existing REST api I'd like to additionally like to add some GRPC api methods to. If in the program.cs for the server, I set kestrel options to use protocols Http1AndHttp2, grpc calls from clients fail.

If I set it to strictly Http2, GRPC works, but rest endpoints do not.

I don't know if this is a limitation of Grpc.Net, or protobuf-net.Grpc, but wondered if there was a way I could "have my cake, and eat it too".

Realize POCO approach in protobuf-net.Grpc.AspNetCore

Hello, Marc.

Earlier you realized POCO approach which was proposed by mythz. I see the method AddCodeFirst in the ServiceDefinitionCollectionExtensions class.
So, I have 2 questions:
1)

 public static int AddCodeFirst<TService>(this ServiceDefinitionCollection services, TService service,
            BinderConfiguration? binderConfiguration = null,
            TextWriter? log = null)
            where TService : class
        {
            var builder = ServerServiceDefinition.CreateBuilder();
            int count = Binder.Create(log).Bind<TService>(builder, binderConfiguration, service);
            services.Add(builder.Build());
            return count;
        }

Can this method be used twice or more times for different services? I really do not understand why this method do not assembly all services marked by marker interface IGrpcService. Could this method be wided for autoassembly all services realized IGrpcService marker interface?

  1. Unfortunatelly, I cannot use this approach on ASP.NET Core project via
    public static IGrpcServerBuilder AddCodeFirstGrpc(this IServiceCollection services, Action<GrpcServiceOptions>? configureOptions).
    Could AddCodeFirstGrpc method be cloned and made similar to the AddCodeFirst method from Native realization?

Thank you.

No gRPC methods discovered

Hi,

I created a service definition using annotations as well as a model using the same method. For some reason, my server cannot discover the gRPC methods for the service definition, neither does the endpoints are implemented. I tried also as suggested on another thread to define the namespace on the ServiceContract with no result (in this case I tried multiple combinations as it was no clear to me if I was supposed to use the server namespace or another project one.)

This is my project structure

+ Solution
     - Api (Client)
     - Appointment2 (gRPC server)
     - Remoting (holds the services definitions as well as the models)

Below an extract of the gRPC server logs

warn: Grpc.AspNetCore.Server.Model.Internal.ServiceRouteBuilder[3]
      No gRPC methods discovered for Appointment2.AppointmentServiceProto.
warn: Microsoft.AspNetCore.Server.Kestrel[0]
      Overriding address(es) 'https://localhost:5001'. Binding to endpoints defined in UseKestrel() instead.
info: Microsoft.Hosting.Lifetime[0]
      Now listening on: http://localhost:5000
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
      Content root path: /Users/josefa/projects/Ally/DHCloud/Appointment2
info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
      Request starting HTTP/2 POST http://localhost:5000/Appointment2.AppointmentServiceProto/Add application/grpc
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0]
      Executing endpoint 'gRPC - gRPC - Unimplemented service'
info: Grpc.AspNetCore.Server.Internal.ServerCallHandlerFactory[1]
      Service 'Appointment2.AppointmentServiceProto' is unimplemented.
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1]
      Executed endpoint 'gRPC - gRPC - Unimplemented service'
info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
      Request finished in 24.012ms 0 application/grpc

This is my service definition

namespace Remoting.AppointmentService
{
    [ProtoContract]
    public class AppointmentListResponse
    {
        [ProtoMember(1)]
        List<Appointment> appointments;
    }


    [ProtoContract]
    public class AppointmentOperationResponse
    {
        [ProtoMember(1)]
        public bool OperationStatus { get; set; }
    }

    [ServiceContract(Name = "Appointment2.AppointmentServiceProto")]
    public interface IAppointmentServiceProtobuf
    {
        ValueTask<AppointmentOperationResponse> AddAsync(Appointment a);
    }
}

Below the service implementation

namespace Appointment2
{
    public class AppointmentServiceProto : IAppointmentServiceProtobuf
    {
        public ValueTask<AppointmentOperationResponse> AddAsync(Appointment a)
        {
            return new ValueTask<AppointmentOperationResponse>(new AppointmentOperationResponse {
                OperationStatus = true
            });
        }
    }
}

I am using Asp.Net core 3.1.0.

To me what becomes remarkable is that Kestrel cannot find the gRPC endpoints, as described on the following warning

warn: Grpc.AspNetCore.Server.Model.Internal.ServiceRouteBuilder[3]
      No gRPC methods discovered for Appointment2.AppointmentServiceProt

I am not sure if this is a bug or that I am missing something.

Thanks a lot.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.