From 8c1bf5b2e194ac960fc91d557ef23206b8eedc62 Mon Sep 17 00:00:00 2001 From: thefringeninja <495495+thefringeninja@users.noreply.github.com> Date: Sat, 2 Feb 2019 12:53:13 +0100 Subject: [PATCH 1/7] try to be helpful --- .../SqlStreamStoreFactory.cs | 54 ++++++++++++++----- 1 file changed, 41 insertions(+), 13 deletions(-) diff --git a/src/SqlStreamStore.Server/SqlStreamStoreFactory.cs b/src/SqlStreamStore.Server/SqlStreamStoreFactory.cs index 39ad5e6..dedd626 100644 --- a/src/SqlStreamStore.Server/SqlStreamStoreFactory.cs +++ b/src/SqlStreamStore.Server/SqlStreamStoreFactory.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Data.SqlClient; +using System.Text; using System.Threading; using System.Threading.Tasks; using Npgsql; @@ -32,10 +33,11 @@ private static readonly IDictionary s_factories public SqlStreamStoreFactory(SqlStreamStoreServerConfiguration configuration) { - if(configuration == null) + if (configuration == null) { throw new ArgumentNullException(nameof(configuration)); } + _configuration = configuration; } @@ -46,7 +48,7 @@ public Task Create(CancellationToken cancellationToken = default) Log.Information($"Creating stream store for provider '{provider}'"); - if(!s_factories.TryGetValue(provider, out var factory)) + if (!s_factories.TryGetValue(provider, out var factory)) { throw new InvalidOperationException($"No provider factory for provider '{provider}' found."); } @@ -69,14 +71,14 @@ private static async Task CreateMssqlStreamStore( CancellationToken cancellationToken) { var connectionStringBuilder = new SqlConnectionStringBuilder(connectionString); - using(var connection = new SqlConnection(new SqlConnectionStringBuilder(connectionString) + using (var connection = new SqlConnection(new SqlConnectionStringBuilder(connectionString) { InitialCatalog = "master" }.ConnectionString)) { await connection.OpenAsync(cancellationToken).NotOnCapturedContext(); - using(var command = new SqlCommand( + using (var command = new SqlCommand( $@" IF NOT EXISTS (SELECT name FROM sys.databases WHERE name = N'{connectionStringBuilder.InitialCatalog}') BEGIN @@ -91,14 +93,21 @@ CREATE DATABASE [{connectionStringBuilder.InitialCatalog}] var settings = new MsSqlStreamStoreV3Settings(connectionString); - if(schema != null) + if (schema != null) { settings.Schema = schema; } var streamStore = new MsSqlStreamStoreV3(settings); - await streamStore.CreateSchemaIfNotExists(cancellationToken); + try + { + await streamStore.CreateSchemaIfNotExists(cancellationToken); + } + catch (SqlException ex) + { + SchemaCreationFailed(streamStore.GetSchemaCreationScript, ex); + } return streamStore; } @@ -110,7 +119,7 @@ private static async Task CreatePostgresStreamStore( { var connectionStringBuilder = new NpgsqlConnectionStringBuilder(connectionString); - using(var connection = new NpgsqlConnection(new NpgsqlConnectionStringBuilder(connectionString) + using (var connection = new NpgsqlConnection(new NpgsqlConnectionStringBuilder(connectionString) { Database = null }.ConnectionString)) @@ -118,7 +127,7 @@ private static async Task CreatePostgresStreamStore( bool exists; await connection.OpenAsync(cancellationToken).NotOnCapturedContext(); - using(var command = new NpgsqlCommand( + using (var command = new NpgsqlCommand( $"SELECT 1 FROM pg_database WHERE datname = '{connectionStringBuilder.Database}'", connection)) { @@ -126,9 +135,9 @@ private static async Task CreatePostgresStreamStore( != null; } - if(!exists) + if (!exists) { - using(var command = new NpgsqlCommand( + using (var command = new NpgsqlCommand( $"CREATE DATABASE {connectionStringBuilder.Database}", connection)) { @@ -138,17 +147,36 @@ private static async Task CreatePostgresStreamStore( var settings = new PostgresStreamStoreSettings(connectionString); - if(schema != null) + if (schema != null) { settings.Schema = schema; } var streamStore = new PostgresStreamStore(settings); - await streamStore.CreateSchemaIfNotExists(cancellationToken); + try + { + await streamStore.CreateSchemaIfNotExists(cancellationToken); + } + catch (NpgsqlException ex) + { + SchemaCreationFailed(streamStore.GetSchemaCreationScript, ex); + } return streamStore; } } + + private static void SchemaCreationFailed(Func getSchemaCreationScript, Exception ex) + => Log.Warning( + new StringBuilder() + .Append($"Could not create schema: {ex.Message}") + .AppendLine() + .Append( + "Does your connection string have enough permissions? If not, run the following sql script as a privileged user:") + .AppendLine() + .Append(getSchemaCreationScript) + .ToString(), + ex); } -} +} \ No newline at end of file From f72c2fc8d29d8e01be017eaf143bc8e634da0e3f Mon Sep 17 00:00:00 2001 From: thefringeninja <495495+thefringeninja@users.noreply.github.com> Date: Thu, 14 Mar 2019 15:07:33 +0100 Subject: [PATCH 2/7] get rid of annoying startup messages --- src/SqlStreamStore.Server/Program.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/SqlStreamStore.Server/Program.cs b/src/SqlStreamStore.Server/Program.cs index d602915..a6c3282 100644 --- a/src/SqlStreamStore.Server/Program.cs +++ b/src/SqlStreamStore.Server/Program.cs @@ -47,6 +47,7 @@ private async Task Run() { using (var streamStore = await _factory.Create(_cts.Token)) using (var host = new WebHostBuilder() + .SuppressStatusMessages(true) .UseKestrel() .UseStartup(new SqlStreamStoreServerStartup(streamStore, new SqlStreamStoreMiddlewareOptions From 234c0e1a215b89a1d75f38a8adb94ab5a29a6b9e Mon Sep 17 00:00:00 2001 From: thefringeninja <495495+thefringeninja@users.noreply.github.com> Date: Thu, 14 Mar 2019 15:31:42 +0100 Subject: [PATCH 3/7] logging config through serilog --- src/SqlStreamStore.Server/Program.cs | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/SqlStreamStore.Server/Program.cs b/src/SqlStreamStore.Server/Program.cs index a6c3282..559e88f 100644 --- a/src/SqlStreamStore.Server/Program.cs +++ b/src/SqlStreamStore.Server/Program.cs @@ -1,6 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Hosting; @@ -17,28 +15,29 @@ internal class Program : IDisposable public static async Task Main(string[] args) { - using (var program = new Program(args)) + var configuration = new SqlStreamStoreServerConfiguration( + Environment.GetEnvironmentVariables(), + args); + + using (var program = new Program(configuration)) { return await program.Run(); } } - private Program(string[] args) + private Program(SqlStreamStoreServerConfiguration configuration) { - _configuration = new SqlStreamStoreServerConfiguration( - Environment.GetEnvironmentVariables(), - args); - - Console.WriteLine(_configuration.ToString()); - Log.Logger = new LoggerConfiguration() - .MinimumLevel.Is(_configuration.LogLevel) + .MinimumLevel.Is(configuration.LogLevel) .Enrich.FromLogContext() .WriteTo.Console() .CreateLogger(); + Log.Information(configuration.ToString()); + + _configuration = configuration; _cts = new CancellationTokenSource(); - _factory = new SqlStreamStoreFactory(_configuration); + _factory = new SqlStreamStoreFactory(configuration); } private async Task Run() @@ -49,7 +48,8 @@ private async Task Run() using (var host = new WebHostBuilder() .SuppressStatusMessages(true) .UseKestrel() - .UseStartup(new SqlStreamStoreServerStartup(streamStore, + .UseStartup(new SqlStreamStoreServerStartup( + streamStore, new SqlStreamStoreMiddlewareOptions { UseCanonicalUrls = _configuration.UseCanonicalUris, From 072c9459fab40ac08597fb5e2abc3ea238e70c0d Mon Sep 17 00:00:00 2001 From: thefringeninja <495495+thefringeninja@users.noreply.github.com> Date: Thu, 14 Mar 2019 15:56:30 +0100 Subject: [PATCH 4/7] fixed schema printing --- src/SqlStreamStore.Server/SqlStreamStoreFactory.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SqlStreamStore.Server/SqlStreamStoreFactory.cs b/src/SqlStreamStore.Server/SqlStreamStoreFactory.cs index dedd626..b6d46c4 100644 --- a/src/SqlStreamStore.Server/SqlStreamStoreFactory.cs +++ b/src/SqlStreamStore.Server/SqlStreamStoreFactory.cs @@ -175,7 +175,7 @@ private static void SchemaCreationFailed(Func getSchemaCreationScript, E .Append( "Does your connection string have enough permissions? If not, run the following sql script as a privileged user:") .AppendLine() - .Append(getSchemaCreationScript) + .Append(getSchemaCreationScript()) .ToString(), ex); } From b44ccaf2e2d6f020c3200912055b290cfacddf08 Mon Sep 17 00:00:00 2001 From: thefringeninja <495495+thefringeninja@users.noreply.github.com> Date: Thu, 14 Mar 2019 15:57:04 +0100 Subject: [PATCH 5/7] better to try catch around anything database --- .../SqlStreamStoreFactory.cs | 118 +++++++++--------- 1 file changed, 59 insertions(+), 59 deletions(-) diff --git a/src/SqlStreamStore.Server/SqlStreamStoreFactory.cs b/src/SqlStreamStore.Server/SqlStreamStoreFactory.cs index b6d46c4..c03654f 100644 --- a/src/SqlStreamStore.Server/SqlStreamStoreFactory.cs +++ b/src/SqlStreamStore.Server/SqlStreamStoreFactory.cs @@ -53,10 +53,7 @@ public Task Create(CancellationToken cancellationToken = default) throw new InvalidOperationException($"No provider factory for provider '{provider}' found."); } - var connectionString = _configuration.ConnectionString; - var schema = _configuration.Schema; - - return factory(connectionString, schema, cancellationToken); + return factory(_configuration.ConnectionString, _configuration.Schema, cancellationToken); } private static Task CreateInMemoryStreamStore( @@ -71,26 +68,6 @@ private static async Task CreateMssqlStreamStore( CancellationToken cancellationToken) { var connectionStringBuilder = new SqlConnectionStringBuilder(connectionString); - using (var connection = new SqlConnection(new SqlConnectionStringBuilder(connectionString) - { - InitialCatalog = "master" - }.ConnectionString)) - { - await connection.OpenAsync(cancellationToken).NotOnCapturedContext(); - - using (var command = new SqlCommand( - $@" -IF NOT EXISTS (SELECT name FROM sys.databases WHERE name = N'{connectionStringBuilder.InitialCatalog}') -BEGIN - CREATE DATABASE [{connectionStringBuilder.InitialCatalog}] -END; -", - connection)) - { - await command.ExecuteNonQueryAsync(cancellationToken).NotOnCapturedContext(); - } - } - var settings = new MsSqlStreamStoreV3Settings(connectionString); if (schema != null) @@ -102,11 +79,32 @@ CREATE DATABASE [{connectionStringBuilder.InitialCatalog}] try { + using (var connection = new SqlConnection(new SqlConnectionStringBuilder(connectionString) + { + InitialCatalog = "master" + }.ConnectionString)) + { + await connection.OpenAsync(cancellationToken).NotOnCapturedContext(); + + using (var command = new SqlCommand( + $@" +IF NOT EXISTS (SELECT name FROM sys.databases WHERE name = N'{connectionStringBuilder.InitialCatalog}') +BEGIN + CREATE DATABASE [{connectionStringBuilder.InitialCatalog}] +END; +", + connection)) + { + await command.ExecuteNonQueryAsync(cancellationToken).NotOnCapturedContext(); + } + } + await streamStore.CreateSchemaIfNotExists(cancellationToken); } catch (SqlException ex) { SchemaCreationFailed(streamStore.GetSchemaCreationScript, ex); + throw; } return streamStore; @@ -118,53 +116,55 @@ private static async Task CreatePostgresStreamStore( CancellationToken cancellationToken) { var connectionStringBuilder = new NpgsqlConnectionStringBuilder(connectionString); + var settings = new PostgresStreamStoreSettings(connectionString); - using (var connection = new NpgsqlConnection(new NpgsqlConnectionStringBuilder(connectionString) - { - Database = null - }.ConnectionString)) + if (schema != null) { - bool exists; - await connection.OpenAsync(cancellationToken).NotOnCapturedContext(); + settings.Schema = schema; + } - using (var command = new NpgsqlCommand( - $"SELECT 1 FROM pg_database WHERE datname = '{connectionStringBuilder.Database}'", - connection)) - { - exists = await command.ExecuteScalarAsync(cancellationToken).NotOnCapturedContext() - != null; - } + var streamStore = new PostgresStreamStore(settings); - if (!exists) + try + { + using (var connection = new NpgsqlConnection(new NpgsqlConnectionStringBuilder(connectionString) { - using (var command = new NpgsqlCommand( - $"CREATE DATABASE {connectionStringBuilder.Database}", - connection)) + Database = null + }.ConnectionString)) + { + await connection.OpenAsync(cancellationToken).NotOnCapturedContext(); + + async Task DatabaseExists() { - await command.ExecuteNonQueryAsync(cancellationToken).NotOnCapturedContext(); + using (var command = new NpgsqlCommand( + $"SELECT 1 FROM pg_database WHERE datname = '{connectionStringBuilder.Database}'", + connection)) + { + return await command.ExecuteScalarAsync(cancellationToken).NotOnCapturedContext() + != null; + } } - } - - var settings = new PostgresStreamStoreSettings(connectionString); - if (schema != null) - { - settings.Schema = schema; - } - - var streamStore = new PostgresStreamStore(settings); + if (!await DatabaseExists()) + { + using (var command = new NpgsqlCommand( + $"CREATE DATABASE {connectionStringBuilder.Database}", + connection)) + { + await command.ExecuteNonQueryAsync(cancellationToken).NotOnCapturedContext(); + } + } - try - { await streamStore.CreateSchemaIfNotExists(cancellationToken); } - catch (NpgsqlException ex) - { - SchemaCreationFailed(streamStore.GetSchemaCreationScript, ex); - } - - return streamStore; } + catch (NpgsqlException ex) + { + SchemaCreationFailed(streamStore.GetSchemaCreationScript, ex); + throw; + } + + return streamStore; } private static void SchemaCreationFailed(Func getSchemaCreationScript, Exception ex) From 5e8c3f3f25bcae086c5ec9d7599f93293591c941 Mon Sep 17 00:00:00 2001 From: thefringeninja <495495+thefringeninja@users.noreply.github.com> Date: Thu, 14 Mar 2019 16:11:36 +0100 Subject: [PATCH 6/7] hide values earlier --- .../SqlStreamStoreServerConfiguration.cs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/SqlStreamStore.Server/SqlStreamStoreServerConfiguration.cs b/src/SqlStreamStore.Server/SqlStreamStoreServerConfiguration.cs index d161851..038d99f 100644 --- a/src/SqlStreamStore.Server/SqlStreamStoreServerConfiguration.cs +++ b/src/SqlStreamStore.Server/SqlStreamStoreServerConfiguration.cs @@ -44,7 +44,11 @@ void Log(string logName, IDictionary data) { foreach (var (key, value) in data) { - _values[key] = (logName, value); + _values[key] = ( + logName, + s_sensitiveKeys.Contains(key) + ? new string('*', 8) + : value); } } @@ -82,18 +86,16 @@ public override string ToString() } } .Concat( - s_allKeys - .Select(key => new[] {delimiter, key, _values[key].value, _values[key].source})) + s_allKeys.Select(key => new[] {delimiter, key, _values[key].value, _values[key].source})) .Aggregate( new StringBuilder().AppendLine("SQL Stream Store Configuration:"), (builder, values) => builder .Append((values[1] ?? string.Empty).PadRight(column0Width, ' ')) .Append(values[0]) - .Append((s_sensitiveKeys.Contains(values[1]) - ? new string('*', Math.Min(column1Width, 8)) - : values[2] ?? string.Empty).PadRight(column1Width, ' ')) + .Append((values[2] ?? string.Empty).PadRight(column1Width, ' ')) .Append(values[0]) - .AppendLine(values[3])).ToString(); + .AppendLine(values[3])) + .ToString(); } private static string Computerize(string value) => From 97dfc911d56f2023e236cf4297d1b7d33ae2e662 Mon Sep 17 00:00:00 2001 From: thefringeninja <495495+thefringeninja@users.noreply.github.com> Date: Thu, 14 Mar 2019 16:11:43 +0100 Subject: [PATCH 7/7] typo --- .../SqlStreamStoreServerConfiguration.cs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/SqlStreamStore.Server/SqlStreamStoreServerConfiguration.cs b/src/SqlStreamStore.Server/SqlStreamStoreServerConfiguration.cs index 038d99f..ace99c2 100644 --- a/src/SqlStreamStore.Server/SqlStreamStoreServerConfiguration.cs +++ b/src/SqlStreamStore.Server/SqlStreamStoreServerConfiguration.cs @@ -117,7 +117,11 @@ private class ConfigurationData public ConfigurationData(IConfigurationRoot configuration) { - if (configuration == null) throw new ArgumentNullException(nameof(configuration)); + if (configuration == null) + { + throw new ArgumentNullException(nameof(configuration)); + } + _configuration = configuration; } } @@ -137,16 +141,20 @@ public Default(Action> log) } public IConfigurationProvider Build(IConfigurationBuilder builder) => - new DefaultConfigurtationProvider(_log); + new DefaultConfigurationProvider(_log); } - private class DefaultConfigurtationProvider : ConfigurationProvider + private class DefaultConfigurationProvider : ConfigurationProvider { private readonly Action> _log; - public DefaultConfigurtationProvider(Action> log) + public DefaultConfigurationProvider(Action> log) { - if (log == null) throw new ArgumentNullException(nameof(log)); + if (log == null) + { + throw new ArgumentNullException(nameof(log)); + } + _log = log; }