当前位置: 首页 > news >正文

WPF consume data generated by grpc services

Install-Package Google.Protobuf
Install-Package Grpc.Net.Client
Install-Package Grpc.Tools
Install-Package Grpc.AspnetCore

 

Add book.proto both in service and client, set the build action as ProtoBuffer Compiler of project properties then rebuild and it will generate related files automatically

syntax="proto3";option csharp_namespace="GrpcBookServer";package book;message  BookProto{int64 id=1;string name=2;string isbn=3;string abstract=4;string author=5;string comment=6;string content=7;string summary=8;string title=9;string topic=10;
}message GetBooksListRequest{int32 cnt=1;
}message GetBooksListResponse{repeated BookProto books=1;
}service BookService
{rpc GetBooksList(GetBooksListRequest) returns (GetBooksListResponse);
}

 

Service

using Google.Protobuf;
using Google.Protobuf.Collections;
using Grpc.Core;
using GrpcBookServer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.Extensions.DependencyInjection;
using System.Runtime.Serialization;
using System.Threading.Tasks.Dataflow;namespace ConsoleApp19
{internal class Program{static void Main(string[] args){GrpcDemo();Console.ReadLine();}static async Task GrpcDemo(){var builder = WebApplication.CreateBuilder();builder.WebHost.ConfigureKestrel(serviceOptions =>{serviceOptions.ListenLocalhost(8888, x => x.Protocols = HttpProtocols.Http2);});builder.Services.AddGrpc(options =>{options.MaxSendMessageSize = null;options.MaxSendMessageSize = null;}); var app = builder.Build();app.MapGrpcService<BookServiceImpl>();Console.WriteLine($"{DateTime.Now},the grpc service started at http://localhost:8888");await app.RunAsync("http://localhost:8888");}}public class BookServiceImpl:BookService.BookServiceBase{private static long id = 0;private static long GetIncrementId(){return Interlocked.Increment(ref id);}public List<Book> GetBooksList(int cnt=1000000){var bksList = new List<Book>();for(int i=0;i<cnt;i++){var a = GetIncrementId();bksList.Add(new Book(){Id=a,Name=$"Name_{a}",ISBN=$"ISBN_{a}_{Guid.NewGuid():N}",Abstract=$"Abstract_{a}",Author=$"Author_{a}",Comment=$"Comment_{a}",Content=$"Content_{a}",Summary=$"Summary_{a}",Title=$"Title_{a}",Topic=$"Topic_{a}"});}return bksList;}public override Task<GetBooksListResponse> GetBooksList(GetBooksListRequest request, ServerCallContext context){var count = request.Cnt is 0 ? 1000000 : request.Cnt;var bksList = GetBooksList(count);var response=new GetBooksListResponse();response.Books.AddRange(bksList.ToProtoList());return Task.FromResult(response);}}public static class BookMapper{public static BookProto ToProtoBook(this Book bk){return new BookProto{Id = bk.Id,Name = bk.Name ?? "",Isbn = bk.ISBN ?? "",Author=bk.Author??"",Abstract = bk.Abstract ?? "",Comment = bk.Comment ?? "",Content = bk.Content ?? "",Summary = bk.Summary ?? "",Title = bk.Title ?? "",Topic = bk.Topic ?? ""};}public static Book ToModel(this BookProto pt){return new Book{Id = pt.Id,Name = pt.Name,ISBN = pt.Isbn,Abstract = pt.Abstract,Author = pt.Author,Comment=pt.Comment,Content=pt.Content,Summary=pt.Summary,Title=pt.Title,Topic=pt.Topic};}public static List<Book> ToModelList(this RepeatedField<BookProto> list){return list.Select(ToModel).ToList();}public static List<BookProto> ToProtoList(this List<Book> list){return list.Select(ToProtoBook).ToList();}}public class Book{public long Id { get; set; }public string Name { get; set; }public string ISBN { get; set; }public string Abstract { get; set; }public string Author { get; set; }public string Comment { get; set; }public string Content { get; set; }public string Summary { get; set; }public string Title { get; set; }public string Topic { get; set; }}}

 

 

Client

<Window x:Class="WpfApp36.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:WpfApp36"mc:Ignorable="d"Title="{Binding MainTitle}" WindowState="Maximized"><Window.DataContext><local:MainVM/></Window.DataContext><Grid><DataGrid ItemsSource="{Binding BooksCollection,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"AutoGenerateColumns="True"CanUserAddRows="False"VirtualizingPanel.IsVirtualizing="True"VirtualizingPanel.VirtualizationMode="Recycling"VirtualizingPanel.CacheLengthUnit="Item"VirtualizingPanel.CacheLength="5,5"ScrollViewer.IsDeferredScrollingEnabled="True"ScrollViewer.CanContentScroll="True"EnableRowVirtualization="True"EnableColumnVirtualization="True"UseLayoutRounding="True"SnapsToDevicePixels="True"><DataGrid.Resources><Style TargetType="DataGridRow"><Setter Property="FontSize" Value="30"/><Style.Triggers><Trigger Property="IsMouseOver" Value="True"><Setter Property="FontSize" Value="40"/><Setter Property="Foreground" Value="Red"/></Trigger></Style.Triggers></Style></DataGrid.Resources></DataGrid></Grid>
</Window>using Google.Protobuf.Collections;
using Grpc.Net.Client;
using GrpcBookServer;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Net.Http;
using System.Runtime.CompilerServices;
using System.Text;
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 System.Windows.Threading;namespace WpfApp36
{/// <summary>/// Interaction logic for MainWindow.xaml/// </summary>public partial class MainWindow : Window{public MainWindow(){InitializeComponent();}}public class MainVM : INotifyPropertyChanged{private DispatcherTimer tmr;private string requestUrl = "http://localhost:8888";GrpcChannel channel;BookService.BookServiceClient client;public MainVM(){if (!DesignerProperties.GetIsInDesignMode(new DependencyObject())){var httpHandler = new HttpClientHandler();httpHandler.ServerCertificateCustomValidationCallback = (_, _, _, _) => true;channel = GrpcChannel.ForAddress(requestUrl, new GrpcChannelOptions{MaxSendMessageSize = null,MaxReceiveMessageSize = null,HttpHandler = httpHandler});client = new BookService.BookServiceClient(channel);_ = LoadBooksCollectionAsync();InitTmr();}}private void InitTmr(){tmr = new DispatcherTimer();tmr.Interval = TimeSpan.FromSeconds(10);tmr.Tick += async (s, e) =>{await LoadBooksCollectionAsync();};tmr.Start();}private async Task LoadBooksCollectionAsync(int cnt = 1000000){MainTitle = $"{DateTime.Now},loading from {requestUrl},cnt={cnt}";var resp = await client.GetBooksListAsync(new GetBooksListRequest { Cnt = cnt });var bksList = resp.Books.ToModelList();if (bksList != null && bksList.Any()){BooksCollection = new ObservableCollection<Book>(bksList);MainTitle = $"{DateTime.Now},loaded {BooksCollection.Count} books,FirstId:{BooksCollection.FirstOrDefault()?.Id},Last Id:{BooksCollection.LastOrDefault()?.Id}";}}private string mainTitle = $"{DateTime.Now},loading...";public string MainTitle{get{return mainTitle;}set{if (value != mainTitle){mainTitle = value;OnPropertyChanged();}}}private ObservableCollection<Book> booksCollection;public ObservableCollection<Book> BooksCollection{get{return booksCollection;}set{if (value != booksCollection){booksCollection = value;OnPropertyChanged();}}}public event PropertyChangedEventHandler? PropertyChanged;private void OnPropertyChanged([CallerMemberName] string propName = ""){var handler = PropertyChanged;handler?.Invoke(this, new PropertyChangedEventArgs(propName));}}public static class BookMapper{public static BookProto ToProtoBook(this Book bk){return new BookProto{Id = bk.Id,Name = bk.Name ?? "",Isbn = bk.ISBN ?? "",Author = bk.Author ?? "",Abstract = bk.Abstract ?? "",Comment = bk.Comment ?? "",Content = bk.Content ?? "",Summary = bk.Summary ?? "",Title = bk.Title ?? "",Topic = bk.Topic ?? ""};}public static Book ToModel(this BookProto pt){return new Book{Id = pt.Id,Name = pt.Name,ISBN = pt.Isbn,Abstract = pt.Abstract,Author = pt.Author,Comment = pt.Comment,Content = pt.Content,Summary = pt.Summary,Title = pt.Title,Topic = pt.Topic};}public static List<Book> ToModelList(this RepeatedField<BookProto> list){return list.Select(ToModel).ToList();}public static List<BookProto> ToProtoList(this List<Book> list){return list.Select(ToProtoBook).ToList();}}public class Book{public long Id { get; set; }public string Name { get; set; }public string ISBN { get; set; }public string Abstract { get; set; }public string Author { get; set; }public string Comment { get; set; }public string Content { get; set; }public string Summary { get; set; }public string Title { get; set; }public string Topic { get; set; }}
}

 

 

 

 

 

image

 

 

 

 

 

 

 

image

 

 

 

 

 

image

 

 

image

 

http://www.jsqmd.com/news/878174/

相关文章:

  • deepseek-tui
  • 洛谷-P11942 [KTSC 2025] 重塑矩阵 题解
  • AppImageLauncher终极指南:10分钟掌握Linux便携应用系统集成
  • 2026年西安防水补漏行业合规经营机构梳理与不同场景消费选型参考 苏州防水补漏维修公司靠谱品牌排名 - 冠盾建筑修缮
  • DeepSeek推理延迟骤降63%?揭秘LLM服务端3层缓存穿透+动态批处理调优全链路
  • 性价比高的广东厂家直销可定制化设计食品级包装袋家电配件注塑家居用品类厂家 - 资讯纵览
  • 泉州汽车音响调音 高端车改装天花板|众毅汽车音响,凭国家级技术硬实力稳居泉州第一 - 汽车音响改装
  • Wonder3D:如何用一张照片在3分钟内创建专业3D模型?
  • 广州华为云代理哪家靠谱?本地华为云合作伙伴大宇云可享专属优惠 - 资讯纵览
  • 泉州新能源汽车音响改装第一|众毅汽车音响,以高压兼容 + 无损协议 + 竞赛调音领跑闽南 - 汽车音响改装
  • DeepSeek API访问控制配置全链路审计(含RBAC+ABAC双模型实测对比)
  • 【DeepSeek生产环境告警零漏报标准】:基于137个真实故障复盘提炼的4层校验机制与SLI/SLO对齐法
  • 探秘镀锌卷板:从“冰火两重天”行业格局看高端汽车钢的突围之道 - 品牌优选官
  • 2026年西安防水补漏领域标杆机构市场格局分析与不同场景选型参考 苏州防水补漏维修公司靠谱品牌排名 - 冠盾建筑修缮
  • 广东厂家直销可定制化设计食品级包装袋家电配件注塑家居用品类厂家 - 资讯纵览
  • 2026 重庆闲置奢包回收品牌推荐:添价收深耕本地回收口碑优良 - 薛定谔的梨花猫
  • 如何快速获取中小学电子课本:国家中小学智慧教育平台下载工具完整指南
  • 合肥GEO优化公司|从技术培训到全案代运营,合肥GEO服务商各司所长 - 行业深度观察C
  • DeepSeek认证失败率骤升40%?揭秘2024Q2新增的3类动态监管要求与5种零代码整改方案
  • LyricsX终极指南:如何在macOS上打造完美的歌词同步体验
  • 荧光法溶解氧仪厂家排行榜:2026国产十大优选品牌深度解析 - 仪表品牌排行榜
  • 2026 年 5 月合肥 GEO 优化公司可靠度深度评估:谁是企业值得托付的 AI 营销伙伴? - 行业深度观察C
  • 2026 重庆玉石翡翠回收机构测评:添价收专业回收获评高分水准 - 薛定谔的梨花猫
  • 2026年最新免费降AI率工具实测:亲测降低AI率至个位数,必备收藏 - 降AI实验室
  • LangChain框架-Agent
  • 【DeepSeek合规白皮书首发】:独家披露2024新版认证评分细则、17项高风险扣分项及应急修复清单
  • 2026年西安本地防水维修行业综合实力分析与头部服务机构全景梳理 苏州防水补漏维修公司靠谱品牌排名 - 冠盾建筑修缮
  • Label Studio终极指南:免费开源的多模态数据标注工具完整教程
  • 2026 重庆黄金首饰回收实力横评:添价收定价标准贴合市场主流 - 薛定谔的梨花猫
  • 2026年小学生练字正姿APP避坑指南:这5款练字软件深度横评 - 品牌报告