我想创建一个简单的WPF核心,gRPC项目。这个“代码”在我的。NET核心控制台应用程序,但是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;
}
在Visual Studio 2019中创建了一个默认模板(使用.NET Core 3.1)
创建了一个默认值。网络核心控制台应用程序-
使用:.NET核心3.1
具有以下 NuGets:
法典
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核心应用程序-
使用:.NET核心3.1
具有以下 NuGets:
法典
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”(是否缺少程序集引用?)
在WPF项目文件中添加这一行,扩展名为“*.csproj”的文件,特别是在标记中
<CoreCompileDependsOn>$(CoreCompileDependsOn);Protobuf_Compile</CoreCompileDependsOn>
它看起来会像这样。csproj文件:
"..."
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net6.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<UseWPF>true</UseWPF>
<CoreCompileDependsOn>$(CoreCompileDependsOn);Protobuf_Compile</CoreCompileDependsOn>
</PropertyGroup>
"..."
此问题与< code>Grpc有关。工具包和WPF应用程序的特殊构建过程。<代码> Grpc。工具包负责编译。原型文件并生成服务类。
解决方案是将gRPC客户端实例化移动到一个单独的. NET Core类库程序集(项目)中。只需将此代码提取到这个新程序集中的一个类,例如GrpcServiceProvider
。让GrpcServiceProvider
返回一个gRPC客户端的实例。现在从您的WPF程序集中引用。NET Core库程序集和GrpcServiceProvider
类以获取客户端的实例。
这将修复构建错误并改进应用程序设计。
不要忘记< code>GrpcChannel实现了< code>IDisposable。这意味着< code>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; }
}
WPF项目
Loaded += async delegate
{
using var serviceProvider = new GrpcServiceProvider();
var client = serviceProvider.GetGreeterClient();
var reply = await client.SayHelloAsync(new HelloRequest { Name = "GreeterClient" });
};