C# WPF.NET内核中的gRPC错误

C# WPF.NET内核中的gRPC错误,c#,wpf,grpc,C#,Wpf,Grpc,我想创建一个简单的WPF核心gRPC项目。这个“代码”在我的.NET核心控制台应用程序中运行得非常好,不过WPF似乎有些特别 原始文件 gRPC服务器 在Visual Studio 2019中创建了默认模板(使用.NET Core 3.1) 控制台应用程序(工作完美) 创建了一个默认的.NET Core控制台应用程序->将原始文件从服务器添加到客户端,并将gRPC存根类更改为仅客户端 用法:.NET Core 3.1 具有以下NUGET: Grpc.工具 Grpc.Net.Client 谷歌

我想创建一个简单的WPF核心gRPC项目。这个“代码”在我的.NET核心控制台应用程序中运行得非常好,不过WPF似乎有些特别

原始文件 gRPC服务器 在Visual Studio 2019中创建了默认模板(使用.NET Core 3.1

控制台应用程序(工作完美) 创建了一个默认的.NET Core控制台应用程序->将原始文件从服务器添加到客户端,并将gRPC存根类更改为仅客户端

用法:.NET Core 3.1

具有以下NUGET:

  • Grpc.工具
  • Grpc.Net.Client
  • 谷歌
代码

WPF.NET内核 创建默认WPF.NET核心应用->将原始文件从服务器添加到客户端,并将gRPC存根类更改为仅客户端

用法:.NET Core 3.1

具有以下NUGET:

  • Grpc.工具
  • Grpc.Net.Client
  • 谷歌
代码

问题

我无法生成WPF应用程序

错误:

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


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

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

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

.NET核心类库项目

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; }
}
Loaded += async delegate
{
    using var serviceProvider = new GrpcServiceProvider();
    var client = serviceProvider.GetGreeterClient();
    var reply = await client.SayHelloAsync(new HelloRequest { Name = "GreeterClient" });
};

您在哪里定义了
.proto
文件?console应用程序的项目文件与WPF应用程序的项目文件有什么区别?@mm8我在每个项目中定义了我的proto文件(例如WPF有他的proto,console有他自己的proto等等)。关于你的第二个问题:没什么,它们都只是客户端,我的grpc服务器原型也有相同的内容,但它只是服务器。
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" });
};
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; }
}
Loaded += async delegate
{
    using var serviceProvider = new GrpcServiceProvider();
    var client = serviceProvider.GetGreeterClient();
    var reply = await client.SayHelloAsync(new HelloRequest { Name = "GreeterClient" });
};