├── .gitattributes ├── .gitignore ├── KestrelHostedWithinIIS ├── KestrelHostedWithinIIS.csproj ├── Program.cs ├── Startup.cs ├── appsettings.Development.json └── appsettings.json ├── README.md ├── WpfAppWithGrpcServer ├── App.xaml ├── App.xaml.cs ├── MainWindow.xaml ├── MainWindow.xaml.cs └── WpfAppWithGrpcServer.csproj ├── gRPCLibrary ├── GrpcServer.cs ├── GrpcServerExtensions.cs ├── GrpcServerOptions.cs ├── Protos │ └── greet.proto ├── Services │ └── GreeterService.cs └── gRPCLibrary.csproj └── gRPCSamples.sln /.gitattributes: -------------------------------------------------------------------------------- 1 | *.doc diff=astextplain 2 | *.DOC diff=astextplain 3 | *.docx diff=astextplain 4 | *.DOCX diff=astextplain 5 | *.dot diff=astextplain 6 | *.DOT diff=astextplain 7 | *.pdf diff=astextplain 8 | *.PDF diff=astextplain 9 | *.rtf diff=astextplain 10 | *.RTF diff=astextplain 11 | 12 | *.jpg binary 13 | *.png binary 14 | *.gif binary 15 | 16 | *.cs text=auto diff=csharp 17 | *.vb text=auto 18 | *.resx text=auto 19 | *.c text=auto 20 | *.cpp text=auto 21 | *.cxx text=auto 22 | *.h text=auto 23 | *.hxx text=auto 24 | *.py text=auto 25 | *.rb text=auto 26 | *.java text=auto 27 | *.html text=auto 28 | *.htm text=auto 29 | *.css text=auto 30 | *.scss text=auto 31 | *.sass text=auto 32 | *.less text=auto 33 | *.js text=auto 34 | *.lisp text=auto 35 | *.clj text=auto 36 | *.sql text=auto 37 | *.php text=auto 38 | *.lua text=auto 39 | *.m text=auto 40 | *.asm text=auto 41 | *.erl text=auto 42 | *.fs text=auto 43 | *.fsx text=auto 44 | *.hs text=auto 45 | 46 | *.csproj text=auto 47 | *.vbproj text=auto 48 | *.fsproj text=auto 49 | *.dbproj text=auto 50 | *.sln text=auto eol=crlf 51 | 52 | *.sh eol=lf -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | [Oo]bj/ 2 | [Bb]in/ 3 | TestResults/ 4 | .nuget/ 5 | *.sln.ide/ 6 | _ReSharper.*/ 7 | .idea/ 8 | packages/ 9 | artifacts/ 10 | PublishProfiles/ 11 | .vs/ 12 | *.user 13 | *.suo 14 | *.cache 15 | *.docstates 16 | _ReSharper.* 17 | nuget.exe 18 | *net45.csproj 19 | *net451.csproj 20 | *k10.csproj 21 | *.psess 22 | *.vsp 23 | *.pidb 24 | *.userprefs 25 | *DS_Store 26 | *.ncrunchsolution 27 | *.*sdf 28 | *.ipch 29 | *.swp 30 | *~ 31 | .build/ 32 | .testPublish/ 33 | launchSettings.json 34 | BenchmarkDotNet.Artifacts/ 35 | BDN.Generated/ 36 | binaries/ 37 | global.json 38 | -------------------------------------------------------------------------------- /KestrelHostedWithinIIS/KestrelHostedWithinIIS.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netcoreapp3.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /KestrelHostedWithinIIS/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Hosting; 6 | using Microsoft.Extensions.Configuration; 7 | using Microsoft.Extensions.Hosting; 8 | using Microsoft.Extensions.Logging; 9 | 10 | namespace KestrelHostedWithinIIS 11 | { 12 | public class Program 13 | { 14 | public static void Main(string[] args) 15 | { 16 | CreateHostBuilder(args).Build().Run(); 17 | } 18 | 19 | public static IHostBuilder CreateHostBuilder(string[] args) => 20 | Host.CreateDefaultBuilder(args) 21 | .ConfigureWebHostDefaults(webBuilder => 22 | { 23 | webBuilder.UseStartup(); 24 | }); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /KestrelHostedWithinIIS/Startup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using gRPCLibrary; 6 | using Microsoft.AspNetCore.Builder; 7 | using Microsoft.AspNetCore.Hosting; 8 | using Microsoft.AspNetCore.Http; 9 | using Microsoft.Extensions.DependencyInjection; 10 | using Microsoft.Extensions.Hosting; 11 | 12 | namespace KestrelHostedWithinIIS 13 | { 14 | public class Startup 15 | { 16 | // This method gets called by the runtime. Use this method to add services to the container. 17 | // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 18 | public void ConfigureServices(IServiceCollection services) 19 | { 20 | services.AddStandaloneGrpcServer(); 21 | } 22 | 23 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 24 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env) 25 | { 26 | if (env.IsDevelopment()) 27 | { 28 | app.UseDeveloperExceptionPage(); 29 | } 30 | 31 | app.UseRouting(); 32 | 33 | app.UseEndpoints(endpoints => 34 | { 35 | endpoints.MapGet("/", async context => 36 | { 37 | await context.Response.WriteAsync("Hello World!"); 38 | }); 39 | }); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /KestrelHostedWithinIIS/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Debug", 5 | "System": "Information", 6 | "Microsoft": "Information" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /KestrelHostedWithinIIS/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | }, 9 | "AllowedHosts": "*" 10 | } 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # gRPC Samples 2 | 3 | Samples showing how to run a gRPC server in a WPF application and as a standalone server running in IIS (Kestrel and IIS running on different ports). 4 | WPF has a known issue generating the appropriate gRPC and proto files (see https://docs.microsoft.com/en-us/aspnet/core/grpc/troubleshoot?view=aspnetcore-3.0#wpf-projects-unable-to-generate-grpc-c-assets-from-proto-files) 5 | so the gRPC service is in a class library. Code generation works fine in web projects but I wanted to share the code. -------------------------------------------------------------------------------- /WpfAppWithGrpcServer/App.xaml: -------------------------------------------------------------------------------- 1 |  6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /WpfAppWithGrpcServer/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Configuration; 4 | using System.Data; 5 | using System.Linq; 6 | using System.Threading.Tasks; 7 | using System.Windows; 8 | 9 | namespace WpfAppWithGrpcServer 10 | { 11 | /// 12 | /// Interaction logic for App.xaml 13 | /// 14 | public partial class App : Application 15 | { 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /WpfAppWithGrpcServer/MainWindow.xaml: -------------------------------------------------------------------------------- 1 |  9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /WpfAppWithGrpcServer/MainWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows; 7 | using System.Windows.Controls; 8 | using System.Windows.Data; 9 | using System.Windows.Documents; 10 | using System.Windows.Input; 11 | using System.Windows.Media; 12 | using System.Windows.Media.Imaging; 13 | using System.Windows.Navigation; 14 | using System.Windows.Shapes; 15 | using gRPCLibrary; 16 | using Microsoft.Extensions.DependencyInjection; 17 | using Microsoft.Extensions.Hosting; 18 | 19 | namespace WpfAppWithGrpcServer 20 | { 21 | /// 22 | /// Interaction logic for MainWindow.xaml 23 | /// 24 | public partial class MainWindow : Window 25 | { 26 | // TODO: Stop this some where... 27 | private IHost _host; 28 | 29 | public MainWindow() 30 | { 31 | _host = new HostBuilder() 32 | .ConfigureServices(services => 33 | { 34 | services.AddStandaloneGrpcServer(o => 35 | { 36 | // Change the port 37 | o.ListenLocalhost(5007); 38 | }); 39 | }) 40 | .Build(); 41 | 42 | _host.Start(); 43 | 44 | InitializeComponent(); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /WpfAppWithGrpcServer/WpfAppWithGrpcServer.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | WinExe 5 | netcoreapp3.0 6 | true 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /gRPCLibrary/GrpcServer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading; 5 | using System.Threading.Tasks; 6 | using Microsoft.AspNetCore.Builder; 7 | using Microsoft.AspNetCore.Hosting; 8 | using Microsoft.AspNetCore.Server.Kestrel.Core; 9 | using Microsoft.Extensions.DependencyInjection; 10 | using Microsoft.Extensions.Hosting; 11 | using Microsoft.Extensions.Logging; 12 | using Microsoft.Extensions.Options; 13 | 14 | namespace gRPCLibrary 15 | { 16 | // This configures a GrpcServer inside of an existing application 17 | public class GrpcServer : IHostedService 18 | { 19 | private IHost _host; 20 | private readonly ILoggerFactory _loggerFactory; 21 | private readonly GrpcServerOptions _options; 22 | 23 | public GrpcServer(ILoggerFactory loggerFactory, IOptions options) 24 | { 25 | _loggerFactory = loggerFactory; 26 | _options = options.Value; 27 | } 28 | 29 | public Task StartAsync(CancellationToken cancellationToken) 30 | { 31 | _host = new HostBuilder() 32 | .ConfigureServices(services => 33 | { 34 | // Add the logger factory so that logs are configured by the main host 35 | services.AddSingleton(_loggerFactory); 36 | }) 37 | .ConfigureWebHost(webHostBuilder => 38 | { 39 | webHostBuilder.UseKestrel(options => 40 | { 41 | options.ConfigureEndpointDefaults(defaults => 42 | { 43 | // gRPC requires HTTP/2 44 | defaults.Protocols = HttpProtocols.Http2; 45 | }); 46 | 47 | _options.ConfigureServerOptions(options); 48 | }); 49 | 50 | webHostBuilder.ConfigureServices(services => 51 | { 52 | services.AddGrpc(options => 53 | { 54 | _options.ConfigureGrpcOptions(options); 55 | }); 56 | }); 57 | 58 | webHostBuilder.Configure(app => 59 | { 60 | app.UseRouting(); 61 | app.UseEndpoints(endpoints => 62 | { 63 | endpoints.MapGrpcService(); 64 | }); 65 | }); 66 | }) 67 | .Build(); 68 | 69 | return _host.StartAsync(cancellationToken); 70 | } 71 | 72 | public Task StopAsync(CancellationToken cancellationToken) 73 | { 74 | return _host?.StopAsync(cancellationToken) ?? Task.CompletedTask; 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /gRPCLibrary/GrpcServerExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using Grpc.AspNetCore.Server; 5 | using gRPCLibrary; 6 | using Microsoft.AspNetCore.Server.Kestrel.Core; 7 | 8 | namespace Microsoft.Extensions.DependencyInjection 9 | { 10 | public static class GrpcServerExtensions 11 | { 12 | public static IServiceCollection AddStandaloneGrpcServer(this IServiceCollection services, 13 | Action configureServer = null, 14 | Action configureGrpc = null) 15 | { 16 | // Add the standalone GrpcServer (it'll only be added once) 17 | services.AddHostedService(); 18 | 19 | services.Configure(options => 20 | { 21 | if (configureServer != null) 22 | { 23 | options.ConfigureServerOptions += configureServer; 24 | } 25 | 26 | if (configureGrpc != null) 27 | { 28 | options.ConfigureGrpcOptions += configureGrpc; 29 | } 30 | }); 31 | return services; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /gRPCLibrary/GrpcServerOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using Grpc.AspNetCore.Server; 5 | using Microsoft.AspNetCore.Server.Kestrel.Core; 6 | 7 | namespace gRPCLibrary 8 | { 9 | public class GrpcServerOptions 10 | { 11 | public Action ConfigureGrpcOptions { get; set; } = o => { }; 12 | public Action ConfigureServerOptions { get; set; } = o => { }; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /gRPCLibrary/Protos/greet.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option csharp_namespace = "GrpcServices"; 4 | 5 | package Greet; 6 | 7 | // The greeting service definition. 8 | service Greeter { 9 | // Sends a greeting 10 | rpc SayHello (HelloRequest) returns (HelloReply); 11 | } 12 | 13 | // The request message containing the user's name. 14 | message HelloRequest { 15 | string name = 1; 16 | } 17 | 18 | // The response message containing the greetings. 19 | message HelloReply { 20 | string message = 1; 21 | } 22 | -------------------------------------------------------------------------------- /gRPCLibrary/Services/GreeterService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Grpc.Core; 6 | using GrpcServices; 7 | using Microsoft.Extensions.Logging; 8 | 9 | namespace gRPCLibrary 10 | { 11 | public class GreeterService : Greeter.GreeterBase 12 | { 13 | private readonly ILogger _logger; 14 | 15 | public GreeterService(ILogger logger) 16 | { 17 | _logger = logger; 18 | } 19 | 20 | public override Task SayHello(HelloRequest request, ServerCallContext context) 21 | { 22 | return Task.FromResult(new HelloReply 23 | { 24 | Message = "Hello " + request.Name 25 | }); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /gRPCLibrary/gRPCLibrary.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netcoreapp3.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /gRPCSamples.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29418.71 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KestrelHostedWithinIIS", "KestrelHostedWithinIIS\KestrelHostedWithinIIS.csproj", "{74E7FDCD-615A-47ED-A0AC-DE87D07C2B0B}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WpfAppWithGrpcServer", "WpfAppWithGrpcServer\WpfAppWithGrpcServer.csproj", "{1CB07795-0327-4308-9ED3-3D56FC5E550A}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "gRPCLibrary", "gRPCLibrary\gRPCLibrary.csproj", "{03A7A3B2-1CFF-4406-9431-A69894A1CD4C}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Release|Any CPU = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {74E7FDCD-615A-47ED-A0AC-DE87D07C2B0B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 | {74E7FDCD-615A-47ED-A0AC-DE87D07C2B0B}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 | {74E7FDCD-615A-47ED-A0AC-DE87D07C2B0B}.Release|Any CPU.ActiveCfg = Release|Any CPU 21 | {74E7FDCD-615A-47ED-A0AC-DE87D07C2B0B}.Release|Any CPU.Build.0 = Release|Any CPU 22 | {1CB07795-0327-4308-9ED3-3D56FC5E550A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {1CB07795-0327-4308-9ED3-3D56FC5E550A}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {1CB07795-0327-4308-9ED3-3D56FC5E550A}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {1CB07795-0327-4308-9ED3-3D56FC5E550A}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {03A7A3B2-1CFF-4406-9431-A69894A1CD4C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {03A7A3B2-1CFF-4406-9431-A69894A1CD4C}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {03A7A3B2-1CFF-4406-9431-A69894A1CD4C}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {03A7A3B2-1CFF-4406-9431-A69894A1CD4C}.Release|Any CPU.Build.0 = Release|Any CPU 30 | EndGlobalSection 31 | GlobalSection(SolutionProperties) = preSolution 32 | HideSolutionNode = FALSE 33 | EndGlobalSection 34 | GlobalSection(ExtensibilityGlobals) = postSolution 35 | SolutionGuid = {403B1E1E-E8DF-4520-8333-CD93A1024561} 36 | EndGlobalSection 37 | EndGlobal 38 | --------------------------------------------------------------------------------