Created
September 4, 2018 19:00
-
-
Save galvesribeiro/6d2f2df6419caaa998857263da057a4b to your computer and use it in GitHub Desktop.
Orleans + Asp.Net Core + GenericHost
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Microsoft.Extensions.Configuration; | |
using Microsoft.Extensions.DependencyInjection; | |
using Microsoft.Extensions.Hosting; | |
using Microsoft.Extensions.Logging; | |
using Orleans; | |
using Orleans.Hosting; | |
using SignalR.Orleans; | |
using System; | |
using System.Collections.Generic; | |
namespace Host | |
{ | |
public static class OrleansExtensions | |
{ | |
private const string SiloBuilderKey = "OrleansSiloBuilderInstance"; | |
private const string ClientBuilderKey = "OrleansClientBuilderInstance"; | |
public static IHostBuilder AddOrleans(this IHostBuilder hostBuilder, Action<ISiloHostBuilder> configure) | |
{ | |
var siloHostBuilder = GetSiloBuilder(hostBuilder); | |
configure?.Invoke(siloHostBuilder); | |
siloHostBuilder.ConfigureDefaults(); | |
siloHostBuilder.GetApplicationPartManager().ConfigureDefaults(); | |
hostBuilder.ConfigureServices(services => | |
{ | |
services.AddHostedService<OrleansHostedService>(); | |
services.AddSingleton<IClusterClientProvider, HostedClusterClientProvider>(); | |
}); | |
return hostBuilder; | |
} | |
public static IHostBuilder AddOrleansClient(this IHostBuilder hostBuilder, Action<IClientBuilder> configure) | |
{ | |
var clientBuilder = GetClientBuilder(hostBuilder); | |
configure?.Invoke(clientBuilder); | |
clientBuilder.ConfigureDefaults(); | |
clientBuilder.GetApplicationPartManager().ConfigureDefaults(); | |
hostBuilder.ConfigureServices(services => | |
{ | |
var client = clientBuilder.Build(); | |
services.AddSingleton(client); | |
services.AddHostedService<OrleansClientHostedService>(); | |
}); | |
return hostBuilder; | |
} | |
private class ClientBuilder : IClientBuilder | |
{ | |
private readonly IHostBuilder hostBuilder; | |
public ClientBuilder(IHostBuilder hostBuilder) | |
{ | |
this.hostBuilder = hostBuilder; | |
} | |
public IDictionary<object, object> Properties => this.hostBuilder.Properties; | |
public IClusterClient Build() => throw new NotSupportedException(); | |
public IClientBuilder ConfigureAppConfiguration(Action<Orleans.Hosting.HostBuilderContext, IConfigurationBuilder> configureDelegate) | |
{ | |
this.hostBuilder.ConfigureAppConfiguration((ctx, cb) => configureDelegate(GetContext(ctx), cb)); | |
return this; | |
} | |
public IClientBuilder ConfigureContainer<TContainerBuilder>(Action<TContainerBuilder> configureContainer) | |
{ | |
this.hostBuilder.ConfigureContainer<TContainerBuilder>((ctx, containerBuilder) => configureContainer(containerBuilder)); | |
return this; | |
} | |
public IClientBuilder ConfigureHostConfiguration(Action<IConfigurationBuilder> configureDelegate) | |
{ | |
this.hostBuilder.ConfigureHostConfiguration(configureDelegate); | |
return this; | |
} | |
public IClientBuilder ConfigureServices(Action<Orleans.Hosting.HostBuilderContext, IServiceCollection> configureDelegate) | |
{ | |
this.hostBuilder.ConfigureServices((ctx, serviceCollection) => configureDelegate(GetContext(ctx), serviceCollection)); | |
return this; | |
} | |
public IClientBuilder UseServiceProviderFactory<TContainerBuilder>(IServiceProviderFactory<TContainerBuilder> factory) | |
{ | |
this.hostBuilder.UseServiceProviderFactory(factory); | |
return this; | |
} | |
} | |
private static IClientBuilder GetClientBuilder(IHostBuilder hostBuilder) | |
{ | |
IClientBuilder clientBuilder; | |
if (hostBuilder.Properties.TryGetValue(ClientBuilderKey, out var value)) | |
{ | |
clientBuilder = value as IClientBuilder; | |
if (clientBuilder == null) throw new InvalidOperationException($"The ClientBuilder value is of the wrong type {value.GetType()}. It should be {nameof(IClientBuilder)}"); | |
} | |
else | |
{ | |
hostBuilder.Properties[ClientBuilderKey] = clientBuilder = new Orleans.ClientBuilder();//new ClientBuilder(hostBuilder); | |
} | |
return clientBuilder; | |
} | |
private class SiloBuilder : ISiloHostBuilder | |
{ | |
private readonly IHostBuilder hostBuilder; | |
public SiloBuilder(IHostBuilder hostBuilder) | |
{ | |
this.hostBuilder = hostBuilder; | |
} | |
public IDictionary<object, object> Properties => this.hostBuilder.Properties; | |
public ISiloHost Build() => throw new NotSupportedException(); | |
public ISiloHostBuilder ConfigureHostConfiguration(Action<IConfigurationBuilder> configureDelegate) | |
{ | |
this.hostBuilder.ConfigureHostConfiguration(configureDelegate); | |
return this; | |
} | |
public ISiloHostBuilder ConfigureAppConfiguration(Action<Orleans.Hosting.HostBuilderContext, IConfigurationBuilder> configureDelegate) | |
{ | |
this.hostBuilder.ConfigureAppConfiguration((ctx, cb) => configureDelegate(GetContext(ctx), cb)); | |
return this; | |
} | |
public ISiloHostBuilder ConfigureServices(Action<Orleans.Hosting.HostBuilderContext, IServiceCollection> configureDelegate) | |
{ | |
this.hostBuilder.ConfigureServices((ctx, serviceCollection) => configureDelegate(GetContext(ctx), serviceCollection)); | |
return this; | |
} | |
public ISiloHostBuilder UseServiceProviderFactory<TContainerBuilder>(IServiceProviderFactory<TContainerBuilder> factory) | |
{ | |
this.hostBuilder.UseServiceProviderFactory(factory); | |
return this; | |
} | |
public ISiloHostBuilder ConfigureContainer<TContainerBuilder>(Action<Orleans.Hosting.HostBuilderContext, TContainerBuilder> configureDelegate) | |
{ | |
this.hostBuilder.ConfigureContainer<TContainerBuilder>((ctx, containerBuilder) => configureDelegate(GetContext(ctx), containerBuilder)); | |
return this; | |
} | |
} | |
private static ISiloHostBuilder GetSiloBuilder(IHostBuilder hostBuilder) | |
{ | |
ISiloHostBuilder siloBuilder; | |
if (hostBuilder.Properties.TryGetValue(SiloBuilderKey, out var value)) | |
{ | |
siloBuilder = value as ISiloHostBuilder; | |
if (siloBuilder == null) throw new InvalidOperationException($"The SiloBuilder value is of the wrong type {value.GetType()}. It should be {nameof(ISiloHostBuilder)}"); | |
} | |
else | |
{ | |
hostBuilder.Properties[SiloBuilderKey] = siloBuilder = new SiloBuilder(hostBuilder); | |
} | |
return siloBuilder; | |
} | |
public static Orleans.Hosting.HostBuilderContext GetContext(Microsoft.Extensions.Hosting.HostBuilderContext ctx) | |
{ | |
var siloContext = new Orleans.Hosting.HostBuilderContext(ctx.Properties) | |
{ | |
Configuration = ctx.Configuration, | |
HostingEnvironment = new HostingEnvironment(ctx.HostingEnvironment) | |
}; | |
return siloContext; | |
} | |
private class HostingEnvironment : Orleans.Hosting.IHostingEnvironment | |
{ | |
private readonly Microsoft.Extensions.Hosting.IHostingEnvironment env; | |
public HostingEnvironment(Microsoft.Extensions.Hosting.IHostingEnvironment env) | |
{ | |
this.env = env; | |
} | |
public string EnvironmentName | |
{ | |
get => this.env.EnvironmentName; | |
set => this.env.EnvironmentName = value; | |
} | |
public string ApplicationName | |
{ | |
get => this.env.ApplicationName; | |
set => this.env.ApplicationName = value; | |
} | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using ES.Stores.Abstractions; | |
using Microsoft.Extensions.DependencyInjection; | |
using Microsoft.Extensions.Hosting; | |
using Microsoft.Extensions.Logging; | |
using Orleans; | |
using Orleans.Hosting; | |
using SignalR.Orleans; | |
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Threading; | |
using System.Threading.Tasks; | |
namespace Host | |
{ | |
internal class OrleansHostedService : IHostedService | |
{ | |
private readonly ISiloHost _siloHost; | |
private readonly ILogger<OrleansHostedService> _logger; | |
private readonly IEnumerable<IConnectableStore> _stores; | |
public OrleansHostedService(ILoggerFactory loggerFactory, ISiloHost siloHost, IServiceProvider serviceProvider) | |
{ | |
this._logger = loggerFactory.CreateLogger<OrleansHostedService>(); | |
this._siloHost = siloHost; | |
this._stores = serviceProvider.GetServices<IConnectableStore>(); | |
} | |
public async Task StartAsync(CancellationToken cancellationToken) | |
{ | |
this._logger.LogInformation($"--------- Starting Orleans Hosted Silo ---------"); | |
if (this._stores?.Count() > 0) | |
{ | |
await Task.WhenAll(this._stores.Select(s => s.Connect())); | |
} | |
await this._siloHost.StartAsync(cancellationToken); | |
this._logger.LogInformation($"--------- Started Orleans Hosted Silo! ---------"); | |
} | |
public async Task StopAsync(CancellationToken cancellationToken) | |
{ | |
this._logger.LogInformation($"--------- Stopping Orleans Hosted Silo ---------"); | |
await this._siloHost.StopAsync(cancellationToken); | |
if (this._stores?.Count() > 0) | |
{ | |
await Task.WhenAll(this._stores.Select(s => s.Disconnect())); | |
} | |
this._logger.LogInformation($"--------- Stopped Orleans Hosted Silo ---------"); | |
} | |
} | |
internal class HostedClusterClientProvider : IClusterClientProvider | |
{ | |
private IClusterClient _clusterClient; | |
public HostedClusterClientProvider(IClusterClient client) | |
{ | |
this._clusterClient = client; | |
} | |
public IClusterClient GetClient() => this._clusterClient; | |
} | |
internal class OrleansClientHostedService : IHostedService | |
{ | |
private readonly IClusterClient _clusterClient; | |
private readonly ILogger<OrleansClientHostedService> _logger; | |
public OrleansClientHostedService(ILoggerFactory loggerFactory, IClusterClient clusterClient) | |
{ | |
this._logger = loggerFactory.CreateLogger<OrleansClientHostedService>(); | |
this._clusterClient = clusterClient; | |
} | |
//public OrleansClientHostedService(ILoggerFactory loggerFactory, IServiceProvider serviceProvider) | |
//{ | |
// this._logger = loggerFactory.CreateLogger<OrleansClientHostedService>(); | |
// serviceProvider.GetService<SerializationManager>().RegisterSerializers(serviceProvider.GetService<IApplicationPartManager>()); | |
// // Construct and return the cluster client. | |
// var asm = typeof(IClusterClient).Assembly; | |
// var runtimeClientType = asm.DefinedTypes.Where(a => a.Name.Contains("OutsideRuntimeClient")).First().AsType(); | |
// var consumeServicesMethod = runtimeClientType.GetMethod("ConsumeServices", BindingFlags.Instance | BindingFlags.NonPublic); | |
// var runtimeClient = serviceProvider.GetRequiredService(runtimeClientType); | |
// consumeServicesMethod.Invoke(runtimeClient, new[] { serviceProvider }); | |
// this._clusterClient = serviceProvider.GetRequiredService<IClusterClient>(); | |
//} | |
public async Task StartAsync(CancellationToken cancellationToken) | |
{ | |
this._logger.LogInformation($"--------- Starting Orleans Hosted Client ---------"); | |
await this._clusterClient.Connect(); | |
} | |
public Task StopAsync(CancellationToken cancellationToken) | |
{ | |
this._logger.LogInformation($"--------- Stopping Orleans Hosted Client ---------"); | |
return this._clusterClient.Close(); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Microsoft.AspNetCore.Hosting; | |
using Microsoft.Extensions.DependencyInjection; | |
using Microsoft.Extensions.Hosting; | |
using Microsoft.Extensions.Logging; | |
using Orleans.Hosting; | |
using System.Threading.Tasks; | |
namespace Host | |
{ | |
class Program | |
{ | |
static async Task Main(string[] args) | |
{ | |
var host = new HostBuilder() | |
.ConfigureLogging((hostContext, configLogging) => | |
{ | |
configLogging.AddConsole(); | |
}) | |
.ConfigureServices(services => | |
{ | |
services.AddOptions(); | |
services.AddLogging(); | |
}) | |
.UseConsoleLifetime() | |
.AddOrleans(builder => builder.AddES()) | |
.AddWeb(builder => builder.AddES()) | |
.Build(); | |
await host.RunAsync(); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Microsoft.AspNetCore.Builder; | |
using Microsoft.AspNetCore.Builder.Internal; | |
using Microsoft.AspNetCore.Hosting; | |
using Microsoft.AspNetCore.Hosting.Builder; | |
using Microsoft.AspNetCore.Hosting.Internal; | |
using Microsoft.AspNetCore.Hosting.Server; | |
using Microsoft.AspNetCore.Http; | |
using Microsoft.Extensions.Configuration; | |
using Microsoft.Extensions.DependencyInjection; | |
using Microsoft.Extensions.Hosting; | |
using Microsoft.Extensions.Logging; | |
using Microsoft.Extensions.ObjectPool; | |
using System; | |
using System.Collections.Generic; | |
using System.Diagnostics; | |
using System.Linq; | |
using System.Reflection; | |
namespace Host | |
{ | |
public static class WebExtensions | |
{ | |
private const string WebBuilderKey = "AspNetBuilderInstance"; | |
public static IHostBuilder AddWeb(this IHostBuilder hostBuilder, Action<IWebHostBuilder> configure) | |
{ | |
hostBuilder.ConfigureHostConfiguration(builder => builder.AddEnvironmentVariables(prefix: "ASPNETCORE_")); | |
var webHostBuilder = GetWebBuilder(hostBuilder); | |
configure?.Invoke(webHostBuilder); | |
hostBuilder.ConfigureServices(services => | |
{ | |
services.AddSingleton(sp => new WebHostOptions( | |
sp.GetRequiredService<IConfiguration>(), Assembly.GetEntryAssembly()?.GetName().Name)); | |
services.AddSingleton<Microsoft.AspNetCore.Hosting.IHostingEnvironment>(sp => | |
{ | |
var hostEnvironment = sp.GetRequiredService<Microsoft.Extensions.Hosting.IHostingEnvironment>(); | |
return new HostingEnvironment | |
{ | |
ApplicationName = hostEnvironment.ApplicationName ?? Assembly.GetEntryAssembly()?.GetName().Name, | |
ContentRootFileProvider = hostEnvironment.ContentRootFileProvider, | |
ContentRootPath = hostEnvironment.ContentRootPath, | |
EnvironmentName = hostEnvironment.EnvironmentName, | |
WebRootFileProvider = hostEnvironment.ContentRootFileProvider, | |
WebRootPath = hostEnvironment.ContentRootPath | |
}; | |
}); | |
var listener = new DiagnosticListener("Microsoft.AspNetCore"); | |
services.AddSingleton<DiagnosticListener>(listener); | |
services.AddSingleton<DiagnosticSource>(listener); | |
services.AddSingleton<Microsoft.AspNetCore.Hosting.IApplicationLifetime, ApplicationLifetime>(); | |
services.AddSingleton(sp => | |
{ | |
return sp.GetRequiredService<Microsoft.AspNetCore.Hosting.IApplicationLifetime>() as Microsoft.Extensions.Hosting.IApplicationLifetime; | |
}); | |
services.AddTransient<IApplicationBuilderFactory, ApplicationBuilderFactory>(); | |
services.AddTransient<IHttpContextFactory, HttpContextFactory>(); | |
services.AddScoped<IMiddlewareFactory, MiddlewareFactory>(); | |
services.AddTransient<IStartupFilter, AutoRequestServicesStartupFilter>(); | |
services.AddTransient<IServiceProviderFactory<IServiceCollection>, DefaultServiceProviderFactory>(); | |
services.AddSingleton<ObjectPoolProvider, DefaultObjectPoolProvider>(); | |
services.AddSingleton(sp => new ApplicationBuilder(sp, sp.GetRequiredService<IServer>().Features)); | |
services.AddSingleton(sp => | |
{ | |
var appBuilder = sp.GetRequiredService<ApplicationBuilder>(); | |
var startup = sp.GetRequiredService<IStartup>(); | |
var startupFilters = sp.GetService<IEnumerable<IStartupFilter>>(); | |
Action<IApplicationBuilder> configureAction = startup.Configure; | |
foreach (var filter in startupFilters.Reverse()) | |
{ | |
configureAction = filter.Configure(configureAction); | |
} | |
configureAction(appBuilder); | |
return new HostingApplication( | |
appBuilder.Build(), | |
sp.GetRequiredService<ILogger<HostingApplication>>(), | |
sp.GetRequiredService<DiagnosticListener>(), | |
sp.GetRequiredService<IHttpContextFactory>()); | |
}); | |
}); | |
hostBuilder.ConfigureServices(services => | |
{ | |
services.AddHostedService<WebHostedService>(); | |
}); | |
return hostBuilder; | |
} | |
private static IWebHostBuilder GetWebBuilder(IHostBuilder hostBuilder) | |
{ | |
IWebHostBuilder webBuilder; | |
if (hostBuilder.Properties.TryGetValue(WebBuilderKey, out var value)) | |
{ | |
webBuilder = value as IWebHostBuilder; | |
if (webBuilder == null) | |
throw new InvalidOperationException( | |
$"The WebHostBuilder value is of the wrong type {value.GetType()}. It should be {nameof(IWebHostBuilder)}"); | |
} | |
else | |
{ | |
hostBuilder.Properties[WebBuilderKey] = webBuilder = new WebBuilder(hostBuilder); | |
} | |
return webBuilder; | |
} | |
private class WebBuilder : IWebHostBuilder | |
{ | |
private readonly IHostBuilder hostBuilder; | |
public WebBuilder(IHostBuilder hostBuilder) | |
{ | |
this.hostBuilder = hostBuilder; | |
} | |
public IWebHost Build() => throw new NotSupportedException(); | |
public IWebHostBuilder ConfigureAppConfiguration(Action<WebHostBuilderContext, IConfigurationBuilder> configureDelegate) | |
{ | |
this.hostBuilder.ConfigureAppConfiguration((ctx, cb) => configureDelegate(GetContext(ctx), cb)); | |
return this; | |
} | |
public IWebHostBuilder ConfigureServices(Action<IServiceCollection> configureServices) | |
{ | |
this.hostBuilder.ConfigureServices(serviceCollection => configureServices(serviceCollection)); | |
return this; | |
} | |
public IWebHostBuilder ConfigureServices(Action<WebHostBuilderContext, IServiceCollection> configureServices) | |
{ | |
this.hostBuilder.ConfigureServices((ctx, serviceCollection) => configureServices(GetContext(ctx), serviceCollection)); | |
return this; | |
} | |
public string GetSetting(string key) => this.hostBuilder.Properties[key].ToString(); | |
public IWebHostBuilder UseSetting(string key, string value) | |
{ | |
this.hostBuilder.Properties[key] = value; | |
return this; | |
} | |
public static WebHostBuilderContext GetContext(HostBuilderContext ctx) | |
{ | |
var siloContext = new WebHostBuilderContext | |
{ | |
Configuration = ctx.Configuration, | |
HostingEnvironment = ctx.HostingEnvironment as Microsoft.AspNetCore.Hosting.Internal.HostingEnvironment | |
}; | |
return siloContext; | |
} | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Microsoft.AspNetCore.Hosting.Internal; | |
using Microsoft.AspNetCore.Hosting.Server; | |
using Microsoft.Extensions.Hosting; | |
using Microsoft.Extensions.Logging; | |
using System.Threading; | |
using System.Threading.Tasks; | |
namespace Host | |
{ | |
internal class WebHostedService : IHostedService | |
{ | |
private readonly ILogger _logger; | |
private readonly IServer _server; | |
private readonly HostingApplication _app; | |
public WebHostedService(ILoggerFactory loggerFactory, IServer server, HostingApplication hostingApplication) | |
{ | |
this._logger = loggerFactory.CreateLogger<WebHostedService>(); | |
this._server = server; | |
this._app = hostingApplication; | |
} | |
public async Task StartAsync(CancellationToken cancellationToken) | |
{ | |
this._logger.LogInformation($"--------- Starting Asp.Net Web Hosted ---------"); | |
await this._server.StartAsync(this._app, cancellationToken); | |
this._logger.LogInformation($"--------- Started Asp.Net Web Hosted! ---------"); | |
} | |
public async Task StopAsync(CancellationToken cancellationToken) | |
{ | |
this._logger.LogInformation($"--------- Stopping Asp.Net Web Hosted ---------"); | |
await this._server.StopAsync(cancellationToken); | |
this._logger.LogInformation($"--------- Stopped Asp.Net Web Hosted! ---------"); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment