WPF .NET Core 中的 gRPC 错误

Posted

技术标签:

【中文标题】WPF .NET Core 中的 gRPC 错误【英文标题】:gRPC erros in WPF .NET Core 【发布时间】:2020-07-03 17:39:03 【问题描述】:

我想创建一个简单的 WPF Core gRPC 项目。此“代码”在我的 .NET Core 控制台应用程序中完美运行,但 WPF 似乎有些特别。

原始文件

syntax = "proto3";

option csharp_namespace = "MyProtoNamespace";

package greet;

// The greeting service definition.
service Greeter 
  // Sends a greeting
  rpc SayHello (HelloRequest) returns (HelloReply);


// The request message containing the user's name.
message HelloRequest 
  string name = 1;


// The response message containing the greetings.
message HelloReply 
  string message = 1;

gRPC 服务器

在 Visual Studio 2019 中创建了一个默认模板(使用 .NET Core 3.1

控制台应用(完美运行)

创建了一个默认的 .NET Core 控制台应用程序 -> 将 Proto 文件从服务器添加到客户端,并将 gRPC Stub Classes 更改为 Client Only

使用:.NET Core 3.1

具有以下 NuGet:

Grpc.Tools Grpc.Net.Client Google.Protobuf

代码

static async Task Main(string[] args) // works perfectly

    using var channel = GrpcChannel.ForAddress("https://localhost:5001");
    var client = new Greeter.GreeterClient(channel);
    var reply = await client.SayHelloAsync(new HelloRequest  Name = "GreeterClient" );

    System.Console.WriteLine("Greeting: " + reply.Message);
    System.Console.WriteLine("Press any key to exit...");
    System.Console.ReadKey();

WPF .NET Core

创建了一个默认的 WPF .NET Core 应用程序 -> 将 Proto 文件从服务器添加到客户端,并将 gRPC Stub Classes 更改为 Client Only

使用:.NET Core 3.1

具有以下 NuGet:

Grpc.Tools Grpc.Net.Client Google.Protobuf

代码

Loaded += async delegate

    using var channel = GrpcChannel.ForAddress("https://localhost:5001");
    var client = new Greeter.GreeterClient(channel);
    var reply = await client.SayHelloAsync(new HelloRequest  Name = "GreeterClient" );
;

问题

我无法构建 WPF 应用程序

错误:

命名空间“MyWPFNameSpace”中不存在类型或命名空间名称“MyProtoNamespace”(您是否缺少程序集引用?)

【问题讨论】:

您在哪里定义了.proto 文件?控制台应用程序的项目文件与 WPF 应用程序的项目文件有什么区别? @mm8 我在每个项目中定义了我的原型文件(例如 WPF 有他的原型,控制台有他自己的等等)。关于你的第二个问题:没什么,它们都只是客户端,我的 grpc 服务器原型也有相同的内容,但它只是服务器。 【参考方案1】:

此问题与Grpc.Tools 包和WPF 应用程序的特殊构建过程有关。 Grpc.Tools包负责编译.proto文件并生成服务类。

解决方案是将 gRPC 客户端实例化移动到单独的 .NET Core 类库程序集(项目)中。只需将此代码提取到一个类中,例如GrpcServiceProvider 在这个新程序集中。让GrpcServiceProvider 返回一个 gRPC 客户端的实例。现在从您的 WPF 程序集中引用 .NET Core 库程序集和 GrpcServiceProvider 类来获取客户端的实例。 这将修复构建错误并改进应用程序设计。

不要忘记GrpcChannel 实现了IDisposable。这意味着GrpcServiceProvider 也应该实现它并正确处置其资源。

.NET Core 类库项目

public class GrpcServiceProvider : IDisposable 

  public GrpcServiceProvider()
  
    this.ServiceUrl = "https://localhost:5001";
    this.DefaultRpcChannel = new Lazy<GrpcChannel>(GrpcChannel.ForAddress(this.ServiceUrl));
  

  public Greeter.GreeterClient GetGreeterClient() => this.GreeterClient ??= new Greeter.GreeterClient(this.DefaultRpcChannel.Value);

  #region IDisposable Support
  private bool disposedValue = false; // To detect redundant calls

  protected virtual void Dispose(bool disposing)
  
    if (!disposedValue)
    
      if (disposing)
      
        if (this.DefaultRpcChannel.IsValueCreated)
        
          this.DefaultRpcChannel.Value.Dispose();
        
      

      // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
      // TODO: set large fields to null.

      disposedValue = true;
    
  

  // TODO: override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources.
  // ~GrpcServiceProvider()
  // 
  //   // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
  //   Dispose(false);
  // 

  // This code added to correctly implement the disposable pattern.
  public void Dispose()
  
    // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
    Dispose(true);
    // TODO: uncomment the following line if the finalizer is overridden above.
    // GC.SuppressFinalize(this);
  

  #endregion IDisposable Support

  private Lazy<GrpcChannel> DefaultRpcChannel  get; set;     
  private string ServiceUrl  get; set;     
  private Greeter.GreeterClient GreeterClient  get; set; 

WPF 项目

Loaded += async delegate

    using var serviceProvider = new GrpcServiceProvider();
    var client = serviceProvider.GetGreeterClient();
    var reply = await client.SayHelloAsync(new HelloRequest  Name = "GreeterClient" );
;

【讨论】:

以上是关于WPF .NET Core 中的 gRPC 错误的主要内容,如果未能解决你的问题,请参考以下文章

[.Net Core] - 在 .NET Core 中创建 gRPC 服务端和客户端

.Net Core gRPC 实战

Asp.net core 通过grpc调用python

.net core grpc consul 实现服务注册 服务发现 负载均衡

gRPC in ASP.NET Core 3.0 -- 前言

gRPC 在.Net core中使用gRPC