public void ClientConfig_ClientInit_FromFile() { const string filename = "ClientConfig_NewAzure.xml"; var client = new ClientBuilder() .ConfigureApplicationParts(parts => parts.AddApplicationPart(typeof(ISimpleGrain).Assembly)) .LoadConfiguration(filename) .Build(); try { ClientConfiguration config = client.Configuration(); output.WriteLine(config); Assert.NotNull(config); // Client.CurrentConfig Assert.Equal(filename, Path.GetFileName(config.SourceFile)); // ClientConfig.SourceFile // GatewayProviderType Assert.Equal(ClientConfiguration.GatewayProviderType.AzureTable, config.GatewayProvider); } finally { client.Dispose(); } }
private static async Task <IClusterClient> InitialiseClient(IConfigurationRoot configuration) { IClusterClient client = null; int tryTimes = 10; while (tryTimes > 0) { try { client = new ClientBuilder() .ConfigureApplicationParts(parts => parts.AddApplicationPart(typeof(IHelloGrain).Assembly)) .Configure <ClusterOptions>(options => { options.ClusterId = configuration.GetSection("ClusterId").Value; options.ServiceId = configuration.GetSection("ServiceId").Value; }) .UseAdoNetClustering(options => { options.Invariant = "System.Data.SqlClient"; options.ConnectionString = configuration.GetSection("ConnectionString").Value; }) .Build(); await client.Connect(); } catch (Exception ex) { Console.WriteLine(ex.Message); } finally { await Task.Delay(TimeSpan.FromSeconds(5)); if (client != null && !client.IsInitialized) { client.Dispose(); client = null; } } tryTimes--; } return(client); }
public async Task LocalhostClusterTest() { using var portAllocator = new TestClusterPortAllocator(); var(baseSiloPort, baseGatewayPort) = portAllocator.AllocateConsecutivePortPairs(2); var silo1 = new HostBuilder().UseOrleans(siloBuilder => { siloBuilder .AddMemoryGrainStorage("MemoryStore") .UseLocalhostClustering(baseSiloPort, baseGatewayPort); }).Build(); var silo2 = new HostBuilder().UseOrleans(siloBuilder => { siloBuilder .AddMemoryGrainStorage("MemoryStore") .UseLocalhostClustering(baseSiloPort + 1, baseGatewayPort + 1, new IPEndPoint(IPAddress.Loopback, baseSiloPort)); }).Build(); var client = new ClientBuilder() .UseLocalhostClustering(new[] { baseGatewayPort, baseGatewayPort + 1 }) .Build(); try { await Task.WhenAll(silo1.StartAsync(), silo2.StartAsync()); await client.Connect(); var grain = client.GetGrain <IEchoGrain>(Guid.NewGuid()); var result = await grain.Echo("test"); Assert.Equal("test", result); } finally { var cancelled = new CancellationTokenSource(); cancelled.Cancel(); Utils.SafeExecute(() => silo1.StopAsync(cancelled.Token)); Utils.SafeExecute(() => silo2.StopAsync(cancelled.Token)); Utils.SafeExecute(() => silo1.Dispose()); Utils.SafeExecute(() => silo2.Dispose()); Utils.SafeExecute(() => client.Close()); Utils.SafeExecute(() => client.Dispose()); } }
public async Task LocalhostClusterTest() { var silo1 = new SiloHostBuilder() .AddMemoryGrainStorage("MemoryStore") .UseLocalhostClustering(12111, 30001) .Build(); var silo2 = new SiloHostBuilder() .AddMemoryGrainStorage("MemoryStore") .UseLocalhostClustering(12112, 30002, new IPEndPoint(IPAddress.Loopback, 12111)) .Build(); var client = new ClientBuilder() .UseLocalhostClustering(new[] { 30001, 30002 }) .Build(); try { await Task.WhenAll(silo1.StartAsync(), silo2.StartAsync()); await client.Connect(); var grain = client.GetGrain <IEchoGrain>(Guid.NewGuid()); var result = await grain.Echo("test"); Assert.Equal("test", result); } finally { var cancelled = new CancellationTokenSource(); cancelled.Cancel(); Utils.SafeExecute(() => silo1.StopAsync(cancelled.Token)); Utils.SafeExecute(() => silo2.StopAsync(cancelled.Token)); Utils.SafeExecute(() => silo1.Dispose()); Utils.SafeExecute(() => silo2.Dispose()); Utils.SafeExecute(() => client.Close()); Utils.SafeExecute(() => client.Dispose()); } }
static void Main(string[] args) { var config = ClientConfiguration.LocalhostSilo(); var client = new ClientBuilder() .LoadConfiguration("../../ClientConfiguration.xml") .Build(); client.Connect().Wait(); Console.WriteLine("Press number or x [Enter] to terminate..."); string nextCommand = ""; while (!(nextCommand.ToUpperInvariant() == "X")) { nextCommand = Console.ReadLine(); var grain = client.GetGrain <ITalkativeGrain>("Grain-" + nextCommand); grain.Talk("Grain-" + nextCommand); } client.Close(); client.Dispose(); }
public static async Task Main(string[] args) { var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Development"; var isDevelopment = "Development".Equals(environment, StringComparison.OrdinalIgnoreCase); var config = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddInMemoryCollection(new Dictionary <string, string> // add default settings, that will be overridden by commandline { { "Id", "Webapp" }, { "Version", "1.0.0" }, { "ClusterId", "rrod-cluster" }, { "ServiceId", "rrod" } }) .AddCommandLine(args) .AddJsonFile("Webapp.settings.json", optional: true, reloadOnChange: true) .AddJsonFile($"Webapp.settings.{environment}.json", optional: true, reloadOnChange: true) .AddJsonFile("/run/config/Webapp.settings.json", optional: true, reloadOnChange: true) .AddDockerSecrets("/run/secrets", optional: true) .AddUserSecrets <Program>(optional: true) .AddEnvironmentVariables("RROD_") .Build(); var loggerFactory = new LoggerFactory() .AddConsole(config.GetSection("Logging")) .AddDebug(); var logger = loggerFactory.CreateLogger <Program>(); logger.LogWarning($"Starting Webapp in {environment} environment..."); foreach (var provider in config.Providers) { logger.LogInformation($"Config Provider {provider.GetType().Name}: {provider.GetChildKeys(Enumerable.Empty<string>(), null).Count()} settings"); } // ServicePointManager.CheckCertificateRevocationList = false; ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12; ServicePointManager.DefaultConnectionLimit = 20; int attempt = 0; int initializeAttemptsBeforeFailing = 7; IClusterClient clusterClient = null; while (true) { // Initialize orleans client clusterClient = new ClientBuilder() .ConfigureServices((context, services) => { // services.AddOptions(); services.AddSingleton <ILoggerFactory>(loggerFactory); // services.AddSingleton<IConfiguration>(config); services.Configure <ClusterOptions>(config); }) .AddAzureQueueStreams <AzureQueueDataAdapterV2>("Default", builder => builder.Configure(options => options.ConnectionString = config.GetConnectionString("DataConnectionString"))) .ConfigureApplicationParts(parts => { parts.AddApplicationPart(typeof(ICounterGrain).Assembly).WithReferences(); parts.AddApplicationPart(typeof(AzureQueueDataAdapterV2).Assembly).WithReferences(); }) .UseAzureStorageClustering(options => options.ConnectionString = config.GetConnectionString("DataConnectionString")) .Build(); try { await clusterClient.Connect().ConfigureAwait(false); logger.LogInformation("Client successfully connected to silo host"); break; } catch (OrleansException) { attempt++; logger.LogWarning($"Attempt {attempt} of {initializeAttemptsBeforeFailing} failed to initialize the Orleans client."); if (clusterClient != null) { clusterClient.Dispose(); clusterClient = null; } if (attempt > initializeAttemptsBeforeFailing) { throw; } // Wait 4 seconds before retrying await Task.Delay(TimeSpan.FromSeconds(4)); } } var endpoints = config.GetSection("Http:Endpoints") .GetChildren() .ToDictionary(section => section.Key, section => { var endpoint = new EndpointConfiguration(); section.Bind(endpoint); return(endpoint); }); // if so, start a listener to respond to Acme (Let's Encrypt) requests, using a response received via an Orleans Cache Grain var hasHttps = endpoints.Any(endpoint => endpoint.Value.Scheme.Equals("https", StringComparison.InvariantCultureIgnoreCase)); var needPort80 = endpoints.Any(endpoint => (endpoint.Value.Port ?? (endpoint.Value.Scheme.Equals("https", StringComparison.InvariantCultureIgnoreCase) ? 443 : 80)) == 80); var certs = new Dictionary <string, X509Certificate2>(); var acmeOptions = new AcmeOptions { AcmeSettings = config.GetSection(nameof(AcmeSettings)).Get <AcmeSettings>(), GetChallengeResponse = async(challenge) => { var cacheGrain = clusterClient.GetGrain <ICacheGrain <string> >(challenge); var response = await cacheGrain.Get(); return(response.Value); }, SetChallengeResponse = async(challenge, response) => { var cacheGrain = clusterClient.GetGrain <ICacheGrain <string> >(challenge); await cacheGrain.Set(new Immutable <string>(response), TimeSpan.FromHours(2)); }, StoreCertificate = async(string domainName, byte[] certData) => { var certGrain = clusterClient.GetGrain <ICertGrain>(domainName); await certGrain.UpdateCertificate(certData); }, RetrieveCertificate = async(domainName) => { var certGrain = clusterClient.GetGrain <ICertGrain>(domainName); var certData = await certGrain.GetCertificate(); return(certData.Value); } }; if (hasHttps) { logger.LogWarning($"At least one https endpoint is present. Initialize Acme endpoint."); var acmeHost = new WebHostBuilder() .UseEnvironment(environment) .UseConfiguration(config) .ConfigureServices(services => { services.AddSingleton <IClusterClient>(clusterClient); services.AddSingleton <ILoggerFactory>(loggerFactory); services.Configure <AcmeSettings>(config.GetSection(nameof(AcmeSettings))); // Register a certitificate manager, supplying methods to store and retreive certificates and acme challenge responses services.AddAcmeCertificateManager(acmeOptions); }) // .UseUrls("http://*:80") .PreferHostingUrls(false) .UseKestrel(options => { options.Listen(IPAddress.Any, 80); }) .Configure(app => { app.UseAcmeResponse(); }) .Build(); try { await acmeHost.StartAsync().ConfigureAwait(false); } catch (Exception e) { logger.LogError("Error: can't start web listener for acme certificate renewal, probably the web address is in use by another process. Exception message is: " + e.Message); logger.LogError("Ignoring noncritical error (stop W3SVC or Skype to fix this), continuing..."); } var certificateManager = acmeHost.Services.GetRequiredService <ICertificateManager>(); // var certificateManager = new AcmeCertificateManager(Options.Create(acmeOptions)); foreach (var endpoint in endpoints) { var endpointConfig = endpoint.Value; bool isHttpsEndpoint = endpointConfig.Scheme.Equals("https", StringComparison.InvariantCultureIgnoreCase); var port = endpointConfig.Port ?? (isHttpsEndpoint ? 443 : 80); X509Certificate2 certificate = null; if (isHttpsEndpoint) { try { var domains = new List <string> { endpointConfig.Domain } .Concat(endpointConfig.Domains) .Where(ep => !string.IsNullOrEmpty(ep)) .Distinct() .ToArray(); logger.LogInformation($"Getting certificate for domain {domains.First()} on port {port}"); // Request a new certificate with Let's Encrypt and store it for next time try { certificate = await certificateManager.GetCertificate(domains); } catch (Exception e) { logger.LogCritical(e, $"Exception getting certificate for domain {domains.First()}. PfxPassword configured incorrectly?"); } if (certificate == null) { // It didn't work - create a temporary certificate so that we can still start with an untrusted certificate logger.LogCritical($"Error getting certificate for domain {domains.First()} (endpoint '{endpoint.Key}'). Creating self-signed temporary certificate..."); certificate = CertHelper.BuildTlsSelfSignedServer(domains); } certs.Add(domains.First(), certificate); logger.LogInformation($"Certificate for domain {domains.First()}: {certificate != null}"); } catch (Exception e) { logger.LogCritical($"Kestrel startup: Exception getting certificate. {e.Message}"); } } } if (needPort80) { await acmeHost.StopAsync(); } } var webHost = new WebHostBuilder() .UseEnvironment(environment) .UseConfiguration(config) .ConfigureServices(services => { // services.AddSingleton<IConfiguration>(config); services.AddSingleton <IClusterClient>(clusterClient); services.AddSingleton <ILoggerFactory>(loggerFactory); services.Configure <AcmeSettings>(config.GetSection(nameof(AcmeSettings))); services.AddAcmeCertificateManager(acmeOptions); }) .UseContentRoot(Directory.GetCurrentDirectory()) // .UseUrls(listenUrls.ToArray()) .PreferHostingUrls(false) .Configure(app => { app.UseAcmeResponse(); }) .UseStartup <Startup>() .UseKestrel(options => { foreach (var endpoint in endpoints) { var endpointConfig = endpoint.Value; bool isHttpsEndpoint = endpointConfig.Scheme.Equals("https", StringComparison.InvariantCultureIgnoreCase); var port = endpointConfig.Port ?? (isHttpsEndpoint ? 443 : 80); var ipAddresses = new List <IPAddress>(); var hosts = new List <string> { endpointConfig.Host } .Concat(endpointConfig.Hosts) .Where(ep => !string.IsNullOrEmpty(ep)) .Distinct(); foreach (var host in hosts) { if (host == "localhost") { ipAddresses.Add(IPAddress.IPv6Loopback); ipAddresses.Add(IPAddress.Loopback); } else if (IPAddress.TryParse(host, out var address)) { ipAddresses.Add(address); } else { logger.LogError($"Error parsing endpoint host: {host}"); } } foreach (var address in ipAddresses) { options.Listen(address, port, listenOptions => { if (isHttpsEndpoint) { var domains = new List <string> { endpointConfig.Domain } .Concat(endpointConfig.Domains) .Where(ep => !string.IsNullOrEmpty(ep)) .Distinct() .ToArray(); if (certs.TryGetValue(domains.First(), out var certificate)) { logger.LogInformation($"Kestrel config: Listen on address {address.ToString()}:{port}, certificate {(certificate == null ? "NULL" : certificate.Subject.ToString())}"); listenOptions.UseHttps(certificate); listenOptions.NoDelay = false; // listenOptions.UseConnectionLogging(); } else { logger.LogError($"No certificate for domain: {domains.First()}"); } } }); } } }) .Build(); await webHost.RunAsync(); }
public static void Main(string[] args) { string environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Development"; bool isDevelopment = "Development".Equals(environment, StringComparison.OrdinalIgnoreCase); var builder = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) .AddJsonFile($"appsettings.{environment}.json", optional: true) .AddEnvironmentVariables(); if (builder.GetFileProvider().GetFileInfo("Webapp.csproj").Exists) { builder.AddUserSecrets <Program>(); } Configuration = builder.Build(); // Initialize the connection to the OrleansHost process var orleansClientConfig = ClientConfiguration.LocalhostSilo(); orleansClientConfig.DeploymentId = Configuration["DeploymentId"]; orleansClientConfig.DataConnectionString = Configuration.GetConnectionString("DataConnectionString"); orleansClientConfig.AddSimpleMessageStreamProvider("Default"); orleansClientConfig.DefaultTraceLevel = Severity.Warning; orleansClientConfig.TraceFileName = ""; IClusterClient orleansClient; do { orleansClient = new ClientBuilder().UseConfiguration(orleansClientConfig).Build(); try { orleansClient.Connect().Wait(); // GrainClient.Initialize(orleansClientConfig); } catch (Exception ex) when(ex is OrleansException || ex is SiloUnavailableException || (ex is AggregateException && ex.InnerException is SiloUnavailableException)) { orleansClient.Dispose(); // Wait for the Host to start Thread.Sleep(3000); } }while (!orleansClient.IsInitialized); // we use a single settings file, that also contains the hosting settings var urls = (Configuration[WebHostDefaults.ServerUrlsKey] ?? "http://localhost:5000") .Split(new[] { ',', ';' }) .Select(url => url.Trim()) .ToArray(); // find out if we run any secure urls var secureUrls = urls .Distinct() .Select(url => new Uri(url)) .Where(uri => uri.Scheme == "https") .ToArray(); // It is possible to request Acme certificates with subject alternative names, but this is not yet implemented. // Usually we'll need only a single address, so I'm taking the first one // string firstSecureHost = secureUrls.Any() ? secureUrls.First().Host : null; var listenUrls = urls .Distinct() .Where(url => url.StartsWith("http://")); // if so, start a listener to respond to Acme (Let's Encrypt) requests, using a response received via an Orleans Cache Grain string[] httpsDomains; IWebHost acmeHost; AcmeOptions acmeOptions; if (!secureUrls.Any()) { httpsDomains = new string[] { }; acmeOptions = null; acmeHost = null; } else { // Kestrel can only listen once to any given port, so we make sure multiple https addresses get only one listener var httpsListen = secureUrls.GroupBy(url => url.Port).Select(url => url.First()).Select(url => "https://*:" + url.Port); listenUrls = listenUrls.Union(httpsListen); httpsDomains = secureUrls.Select(url => url.Host).Distinct().ToArray(); acmeOptions = new AcmeOptions { DomainNames = httpsDomains, GetChallengeResponse = async(challenge) => { var cacheGrain = orleansClient.GetGrain <ICacheGrain <string> >(challenge); var response = await cacheGrain.Get(); return(response.Value); }, SetChallengeResponse = async(challenge, response) => { var cacheGrain = orleansClient.GetGrain <ICacheGrain <string> >(challenge); await cacheGrain.Set(new Immutable <string>(response), TimeSpan.FromHours(2)); }, StoreCertificate = async(string domainName, byte[] certData) => { var certGrain = orleansClient.GetGrain <ICertGrain>(domainName); await certGrain.UpdateCertificate(certData); }, RetrieveCertificate = async(domainName) => { var certGrain = orleansClient.GetGrain <ICertGrain>(domainName); var certData = await certGrain.GetCertificate(); return(certData.Value); } }; acmeHost = new WebHostBuilder() .UseConfiguration(Configuration) .ConfigureLogging((context, factory) => { factory.AddConfiguration(context.Configuration.GetSection("Logging")); factory.AddConsole(); factory.AddDebug(); }) .UseEnvironment(environment) .ConfigureServices(services => { services.AddSingleton <IClusterClient>(orleansClient); services.Configure <AcmeSettings>(Configuration.GetSection(nameof(AcmeSettings))); // Register a certitificate manager, supplying methods to store and retreive certificates and acme challenge responses services.AddAcmeCertificateManager(acmeOptions); }) .UseUrls("http://*:80/.well-known/acme-challenge/") .UseKestrel() // .UseLoggerFactory(loggerFactory) .Configure(app => { app.UseAcmeResponse(); }) .Build(); try { acmeHost.Start(); } catch (Exception e) { var logger = acmeHost.Services.GetService <ILogger <Program> >(); // var logger = loggerFactory.CreateLogger<Program>(); logger.LogError("Error: can't start web listener for acme certificate renewal, probably the web address is in use by another process. Exception message is: " + e.Message); logger.LogError("Ignoring noncritical error (stop W3SVC or Skype to fix this), continuing..."); } } var host = new WebHostBuilder() .UseConfiguration(Configuration) .ConfigureLogging((context, factory) => { factory.AddConfiguration(context.Configuration.GetSection("Logging")); factory.AddConsole(); factory.AddDebug(); }) .ConfigureServices(services => { services.AddSingleton <IClusterClient>(orleansClient); if (secureUrls.Any()) { services.AddAcmeCertificateManager(acmeOptions); } }) .UseContentRoot(Directory.GetCurrentDirectory()) .UseEnvironment(environment) .UseUrls(listenUrls.ToArray()) .UseSetting("baseUrl", urls.First()) .UseStartup <Startup>() .UseKestrel(async options => { // TODO: Make this into a nice Kestrel.Https.Acme nuget package if (secureUrls.Any()) { // Request a new certificate with Let's Encrypt and store it for next time var certificateManager = options.ApplicationServices.GetService <ICertificateManager>(); var certificate = await certificateManager.GetCertificate(httpsDomains); if (certificate != null) { options.Listen(IPAddress.Loopback, 443, listenOptions => { listenOptions.UseHttps(certificate); }); } } }) .Build(); host.Run(); }