Skip to content

Instantly share code, notes, and snippets.

@galvesribeiro
Created September 4, 2018 19:00
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save galvesribeiro/6d2f2df6419caaa998857263da057a4b to your computer and use it in GitHub Desktop.
Save galvesribeiro/6d2f2df6419caaa998857263da057a4b to your computer and use it in GitHub Desktop.
Orleans + Asp.Net Core + GenericHost
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;
}
}
}
}
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();
}
}
}
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();
}
}
}
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;
}
}
}
}
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