Skip to content

Instantly share code, notes, and snippets.

@schmitch
Created June 30, 2020 14:49
Show Gist options
  • Save schmitch/585fe6cd4e61151c3b9224435210bb8d to your computer and use it in GitHub Desktop.
Save schmitch/585fe6cd4e61151c3b9224435210bb8d to your computer and use it in GitHub Desktop.
standalone grpc server builder
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting.Builder;
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace WorkerWebProject
{
public class GrpcServerBuilder
{
private readonly KestrelServerOptions _kestrelServerOptions;
private readonly SocketTransportOptions _socketTransportOptions = new SocketTransportOptions();
private Action<IApplicationBuilder> _pipelineAction = null;
private readonly List<Action<IEndpointRouteBuilder>> _routes = new List<Action<IEndpointRouteBuilder>>();
private GrpcServerBuilder(KestrelServerOptions kestrelServerOptions)
{
_kestrelServerOptions = kestrelServerOptions;
}
public static GrpcServerBuilder Create(int port, Action<ListenOptions> listenOptions = null)
{
var options = new KestrelServerOptions();
options.ListenLocalhost(port, listenOptions ?? (o => o.Protocols = HttpProtocols.Http2));
return new GrpcServerBuilder(options);
}
public GrpcServerBuilder ConfigureKestrel(Action<KestrelServerOptions> options)
{
options(_kestrelServerOptions);
return this;
}
public GrpcServerBuilder ConfigureSocketTransport(Action<SocketTransportOptions> options)
{
options(_socketTransportOptions);
return this;
}
public GrpcServerBuilder AddPipeline(Action<IApplicationBuilder> app)
{
_pipelineAction = app;
return this;
}
public GrpcServerBuilder AddService<T>() where T : class
{
_routes.Add(e => e.MapGrpcService<T>());
return this;
}
public GrpcWorker Build(IServiceProvider provider)
{
return new GrpcWorker(_kestrelServerOptions, provider, _socketTransportOptions, _routes, _pipelineAction);
}
private class GrpcApplication : IHttpApplication<HttpContext>
{
private readonly RequestDelegate _request;
private readonly IHttpContextFactory _httpContextFactory;
public GrpcApplication(RequestDelegate request, IServiceProvider provider)
{
_request = request;
_httpContextFactory = new DefaultHttpContextFactory(provider);
}
public HttpContext CreateContext(IFeatureCollection contextFeatures)
{
return _httpContextFactory.Create(contextFeatures);
}
public void DisposeContext(HttpContext context, Exception exception)
{
_httpContextFactory.Dispose(context);
}
public async Task ProcessRequestAsync(HttpContext context)
{
await _request(context);
}
}
public class GrpcWorker : IHostedService
{
private KestrelServer _server;
private readonly KestrelServerOptions _kestrelServerOptions;
private readonly IServiceProvider _provider;
private readonly SocketTransportOptions _socketTransportOptions;
private readonly List<Action<IEndpointRouteBuilder>> _routes;
private readonly Action<IApplicationBuilder> _pipelineAction;
internal GrpcWorker(
KestrelServerOptions kestrelServerOptions,
IServiceProvider provider,
SocketTransportOptions socketTransportOptions,
List<Action<IEndpointRouteBuilder>> routes,
Action<IApplicationBuilder> pipelineAction)
{
_kestrelServerOptions = kestrelServerOptions;
_provider = provider;
_socketTransportOptions = socketTransportOptions;
_routes = routes;
_pipelineAction = pipelineAction;
}
public async Task StartAsync(CancellationToken cancellationToken)
{
var loggerFactory = _provider.GetRequiredService<ILoggerFactory>();
var socketTransportFactory = new SocketTransportFactory(
Options.Create(_socketTransportOptions),
loggerFactory);
_server = new KestrelServer(
Options.Create(_kestrelServerOptions),
socketTransportFactory,
loggerFactory);
var builder = new ApplicationBuilderFactory(_provider).CreateBuilder(_server.Features);
_pipelineAction?.Invoke(builder);
builder.UseRouting();
builder.UseEndpoints(e =>
{
foreach (var action in _routes)
{
action(e);
}
});
var requestDelegate = builder.Build();
await _server.StartAsync(new GrpcApplication(requestDelegate, _provider), cancellationToken);
}
public async Task StopAsync(CancellationToken cancellationToken)
{
await _server.StopAsync(cancellationToken);
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment