上記の最も簡単な gRPCサービスと通信するWPFアプリのサンプルコードを解説する。
コンソールアプリのときと同じで、.NET8.0 を使用する。(2024/01/15更新)
具体的なサンプルコードのプロジェクトファイルは以下のGitHUBリポジトリから公開しています。
通信相手となる gRPCサービスはコンソールアプリの通信相手と同じで、以下のプロジェクトになります。
WPFプロジェクトでもコンソールアプリと同じ、三つのNuGetパッケージを使用する。
その内、「Grpc.Tools」はWPFプロジェクトでは使用できない。
インストールする事はできるが、コンパイルエラーになりビルドできない。
WPFアプリで「Grpc.Tools」を使用して gRPC通信をするには、WPFプロジェクトと別にクラスライブラリのプロジェクトを作成し「Grpc.Tools」をクラスライブラリ側にインストールして、WPFプロジェクト側からクラスライブラリ・プロジェクトを参照する必要がある。
以下に手順を説明する。
必要なプロジェクトの作成
Visual Studio 2022 で、gRPCサービスのプロジェクトを開いておく。
もう一つ Visual Studio 2022 を起動して、「新しいプロジェクトの作成」を開き、フィルターを「C#」「すべてのプラットフォーム」「デスクトップ」で絞り込んで、「WPF App (.NET)」を選択して開く。
プロジェクト名、場所、ソリューション名などは任意で名付けます。
WPFプロジェクトが作成されたら、ソリューションエクスプローラーのソリューションを右クリックして、ポップアップメニューから「追加」の中の「新しいプロジェクト」を選ぶ。
「新しいプロジェクトの作成」画面が開き、フィルターを「C#」「すべてのプラットフォーム」「ライブラリ」で絞り込んで、「クラスライブラリ (.NET Standard)」を選択して開く。
プロジェクト名は任意で名付けます。
ソリューションエクスプローラーからクラスライブラリのプロジェクトを右クリックして、ポップアップメニューから「プロパティ」を選ぶ。
「アプリケーション」の設定の「対象のフレームワーク」を「.NET Standard 2.1」以上に変更する。
ソリューションエクスプローラーからWPFプロジェクトを右クリックして、ポップアップメニューから「追加」の中の「プロジェクト参照」を選ぶ。
クラスライブラリのプロジェクトに参照を意味するチェックマークを付けて「OK」ボタンを押す。
NuGetパッケージのインストール
これから、作成した両方のプロジェクトの画面右上にある「ソリューションエクスプローラー」の該当プロジェクトを右クリックして、ポップアップメニューから「NuGetパッケージの管理」を選び NuGetパッケージをそれぞれにインストールする。
まずはクラスライブラリ・プロジェクトのNuGetパッケージをインストールする。
インストール対象となるNuGetパッケージは以下の三つである。
Google.Protobuf
Grpc.Net.Client
Grpc.Tools
次にWPFプロジェクトのNuGetパッケージをインストールする。
インストール対象となるNuGetパッケージは以下の二つである。
Google.Protobuf
Grpc.Net.Client
「ソリューションエクスプローラー」それぞれのプロジェクトの「依存関係」の下の「パッケージ」の下にインストールしたNuGetパッケージが登録されているはずだ。
Protobuf の定義を登録
gRPCサービスのプロジェクトから「Protosgreet.proto」ファイルをフォルダーごと、クラスライブラリ・プロジェクトへコピーする。
二つのプロジェクトをVisual Studio二重起動で両方開き、「ソリューションエクスプローラー」から、フォルダーをコピー・ペーストできるはずだ。
「greet.proto」ファイルの編集
そしてクラスライブラリのプロジェクトから「greet.proto」ファイルを開き、「option csharp_namespace」の値をクラスライブラリの「namespace」の値に書き換える。
ちなみに「namespace」の値はクラスライブラリの「Class1.cs」に書かれている。
サンプルコードでは「Sample_gRPC_ClassLibrary」となっている。
[greet.proto]ファイル
syntax = "proto3";
option csharp_namespace = "Sample_gRPC_ClassLibrary";
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;
}
プロジェクトファイルの編集
次に「ソリューションエクスプローラー」からクラスライブラリのプロジェクトファイルをダブルクリックしてソースを開き、 ItemGroup ダグの中で Protobuf タグを定義する。
編集後のプロジェクトファイル
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<Protobuf Include="Protosgreet.proto" GrpcServices="Client" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Google.Protobuf" Version="3.14.0" />
<PackageReference Include="Grpc.Net.Client" Version="2.34.0" />
<PackageReference Include="Grpc.Tools" Version="2.35.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
</Project>
追加したのは以下のコードだ。
<ItemGroup>
<Protobuf Include="Protosgreet.proto" GrpcServices="Client" />
</ItemGroup>
これが 「greet.proto」を参照する事と、それがクライアント用である事を定義している。
.NET5.0 の場合
もし .NET5.0の場合は、WPFのプロジェクトファイルのソースコードの先頭にある Project タグの Sdk プロパティの値を以下のように変更する必要がある。
[変更前]
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
[変更後]
<Project Sdk="Microsoft.NET.Sdk">
画面レイアウトの記述
「MainWindow.xaml」に画面レイアウトを書いておく。
画面の作り方は普通のWPFと同じである。
xaml のソースだけここに記述しておく。
<Window x:Class="Sample_gRPC_WpfApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Sample_gRPC_WpfApp"
mc:Ignorable="d"
Title="Sample gRPC-WPF" Height="100" Width="500">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="20" />
<RowDefinition />
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal" Grid.Row="0">
<TextBlock Text="リクエスト文字列" Width="100" Margin="20,0,0,0" />
<TextBox x:Name="ReqestTextBox" Width="200" />
<Button x:Name="ReqestButton" Content="リクエスト" Width="100" Click="ReqestButton_Click"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Grid.Row="1" Height="20" VerticalAlignment="Top">
<TextBlock Text="リプライ" Width="100" Margin="20,0,0,0" />
<TextBox x:Name="ReplayTextBox" Width="300" />
</StackPanel>
</Grid>
</Window>
ReqestButton を押すと、ReqestTextBox の値を gRPCサービスに送り、返ってきた結果を ReplayTextBox へ記述する。
メイン処理の記述
WPFプロジェクトの「MainWindow.xaml.cs」と、クラスライブラリ・プロジェクトの「Class1.cs」にgRPCサービスと通信するメイン処理を書き込む。
「Class1.cs」では分かりにくいので、分かりやすいクラス名に変更する。
ソリューションエクスプローラーから変更できる。
仮に「SampleClient.cs」とする。
「SampleClient.cs」にgRPCサービスと通信するメイン処理を書き込む。
[SampleClient.cs]ファイル
using System;
using Grpc.Net.Client;
namespace Sample_gRPC_ClassLibrary
{
public class SampleClient
{
public SampleClient()
{
this.serviceUrl = "https://localhost:5001";
this.grpcChannel = GrpcChannel.ForAddress(this.serviceUrl);
this.greeterClient = new Greeter.GreeterClient(this.grpcChannel);
}
private string serviceUrl = null;
private GrpcChannel grpcChannel = null;
private Greeter.GreeterClient greeterClient = null;
public GrpcChannel Channel
{
get { return this.grpcChannel; }
}
public Greeter.GreeterClient GreeterClient
{
get { return this.greeterClient; }
}
}
}
「using Grpc.Net.Client;」を最初に追加してGrpcライブラリを参照できるようにする。
コンストラクタで
「this.grpcChannel = GrpcChannel.ForAddress(this.serviceUrl);」により、
gRPCサービスとのセッションを確立し、
「this.greeterClient = new Greeter.GreeterClient(this.grpcChannel);」で、
「greet.protp」ファイルで定義した「service Greeter」のインスタンスを作成する。
それぞれのインスタンスを「SampleClient」のプロパティに持たせて、外から参照できるようにしておく。
xaml イベントに通信処理を記述する
WPFプロジェクトの「MainWindow.xaml.cs」の ReqestButton のクリックイベントを作成し、そこに「SampleClient」を呼び出す処理を記述する。
[MainWindow.xaml.cs]ファイル
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Grpc.Net.Client;
using Sample_gRPC_ClassLibrary;
namespace Sample_gRPC_WpfApp
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void ReqestButton_Click(object sender, RoutedEventArgs e)
{
string requestText = this.ReqestTextBox.Text;
SampleClient grpcClient = new SampleClient();
var reply = grpcClient.GreeterClient.SayHello(new HelloRequest { Name = requestText });
this.ReplayTextBox.Text = reply.Message;
}
}
}
using で「Grpc.Net.Client;」と「Sample_gRPC_ClassLibrary;」を追加し、
ReqestButton_Click に以下の処理を追加している。
string requestText = this.ReqestTextBox.Text;
SampleClient grpcClient = new SampleClient();
var reply = grpcClient.GreeterClient.SayHello(new HelloRequest { Name = requestText });
this.ReplayTextBox.Text = reply.Message;
SampleClient のインスタンスを作成して、先ほどコンストラクタに書いた処理を実行する。
SampleClient のインスタンスにある、GreeterClient から、SayHello API を呼び出し、結果を表示する。
ビルドして実行する
ビルドする前に、gRPCサービスを実行しておく。
初めてgRPCアプリをビルドして実行すると、ローカル開発用のSSLの暗号キーを作成する旨の確認画面が表示される。
これは「OK」して先に進む。
これは一度しか出てこない。
環境によって、gRPCサービスへのアクセスが拒否されてしまう場合もある。
これは大半がSSLの認証設定ができていないのが原因である。
HTTPSのアドレスにアクセスするには、ASP.NET Core HTTPS 開発証明書を信頼する設定を実施する必要がある。ターミナルのコマンドラインで以下のコマンドを実行するとそれができる。
dotnet dev-certs https –trust
開発証明書はSDKと一緒にインストールされている。
開発証明書についての解説は以下のサイトで行われている。
Windows と macOS で ASP.NET Core HTTPS 開発証明書を信頼する
クライアントアプリを起動すると、WPFの画面が起動するので、リクエスト文字列に自分の名前を記述して、「リクエスト」ボタンをクリックする。
リプライに「Hello 自分の名前」と表示されるはずだ。
以上、WPFアプリによるgRPCサービスとの通信処理の最も簡単な作り方でした。