

























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; } } }




此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。