【问题标题】:gRPC erros in WPF .NET CoreWPF .NET Core 中的 gRPC 错误
【发布时间】: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 服务器原型也有相同的内容,但它只是服务器。

标签: c# 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" });
};

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-02-04
    • 2021-08-10
    • 2020-11-12
    • 2020-08-22
    • 1970-01-01
    • 1970-01-01
    • 2020-04-03
    相关资源
    最近更新 更多