From 82945fb124bc3dc62d242579e7c9b4a7909f6660 Mon Sep 17 00:00:00 2001 From: martincostello Date: Thu, 18 Feb 2021 10:51:41 +0000 Subject: [PATCH 01/29] Update to .NET 6 preview 1 Update to preview 1 of .NET 6. --- .github/workflows/build.yml | 2 +- Directory.Packages.props | 16 ++++++++-------- global.json | 2 +- readme.md | 2 +- samples/TodoApp.Tests/TodoApp.Tests.csproj | 2 +- samples/TodoApp/TodoApp.csproj | 2 +- src/SqlLocalDb/MartinCostello.SqlLocalDb.csproj | 2 +- .../MartinCostello.SqlLocalDb.TestApp.csproj | 2 +- .../MartinCostello.SqlLocalDb.Tests.csproj | 2 +- 9 files changed, 16 insertions(+), 16 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 15b0979b..33268a69 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -44,7 +44,7 @@ jobs: - uses: codecov/codecov-action@v1 name: Upload coverage to Codecov with: - file: ./artifacts/coverage.net5.0.cobertura.xml + file: ./artifacts/coverage.net6.0.cobertura.xml flags: ${{ matrix.os_name }} - name: Publish artifacts diff --git a/Directory.Packages.props b/Directory.Packages.props index 0c2b1def..da243997 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -7,7 +7,7 @@ - + @@ -26,17 +26,17 @@ - + - - - + + + - - - + + + diff --git a/global.json b/global.json index fc0042e0..25408d36 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "5.0.402", + "version": "6.0.100-preview.1.21103.13", "allowPrerelease": false, "rollForward": "latestMajor" } diff --git a/readme.md b/readme.md index 5167c232..38913986 100644 --- a/readme.md +++ b/readme.md @@ -80,7 +80,7 @@ This project is licensed under the [Apache 2.0](http://www.apache.org/licenses/L ## Building and Testing -Compiling the library yourself requires Git and the [.NET SDK](https://www.microsoft.com/net/download/core "Download the .NET SDK") to be installed (version `5.0.100` or later). +Compiling the library yourself requires Git and the [.NET SDK](https://www.microsoft.com/net/download/core "Download the .NET SDK") to be installed (version `6.0.100` or later). For all of the tests to be functional you must also have at least one version of SQL LocalDB installed. diff --git a/samples/TodoApp.Tests/TodoApp.Tests.csproj b/samples/TodoApp.Tests/TodoApp.Tests.csproj index ca24d4e7..277b2c9d 100644 --- a/samples/TodoApp.Tests/TodoApp.Tests.csproj +++ b/samples/TodoApp.Tests/TodoApp.Tests.csproj @@ -3,7 +3,7 @@ false $(NoWarn);CA1303;CA1707;CA2007;SA1600 TodoApp - net5.0 + net6.0 false diff --git a/samples/TodoApp/TodoApp.csproj b/samples/TodoApp/TodoApp.csproj index 9df96ca5..1c4f0180 100644 --- a/samples/TodoApp/TodoApp.csproj +++ b/samples/TodoApp/TodoApp.csproj @@ -4,7 +4,7 @@ false $(NoWarn);CA1062;CA1303;CA1822;CA2007;CA2227;SA1600 TodoApp - net5.0 + net6.0 diff --git a/src/SqlLocalDb/MartinCostello.SqlLocalDb.csproj b/src/SqlLocalDb/MartinCostello.SqlLocalDb.csproj index c354e55a..899732bb 100644 --- a/src/SqlLocalDb/MartinCostello.SqlLocalDb.csproj +++ b/src/SqlLocalDb/MartinCostello.SqlLocalDb.csproj @@ -8,7 +8,7 @@ MartinCostello.SqlLocalDb MartinCostello.SqlLocalDb $(Description) - netstandard2.0 + netstandard2.0;net6.0 SQL LocalDB Wrapper diff --git a/src/TestApp/MartinCostello.SqlLocalDb.TestApp.csproj b/src/TestApp/MartinCostello.SqlLocalDb.TestApp.csproj index 2a729988..1a13161f 100644 --- a/src/TestApp/MartinCostello.SqlLocalDb.TestApp.csproj +++ b/src/TestApp/MartinCostello.SqlLocalDb.TestApp.csproj @@ -5,7 +5,7 @@ $(NoWarn);CA1031;CA2007;SA1600 Exe MartinCostello.SqlLocalDb - net5.0 + net6.0 diff --git a/tests/SqlLocalDb.Tests/MartinCostello.SqlLocalDb.Tests.csproj b/tests/SqlLocalDb.Tests/MartinCostello.SqlLocalDb.Tests.csproj index eef65d74..fe9515a6 100644 --- a/tests/SqlLocalDb.Tests/MartinCostello.SqlLocalDb.Tests.csproj +++ b/tests/SqlLocalDb.Tests/MartinCostello.SqlLocalDb.Tests.csproj @@ -7,7 +7,7 @@ true MartinCostello.SqlLocalDb $(Description) - net5.0 + net6.0 From 7edd08f04a04381398e4d89359e23a8bb06892bd Mon Sep 17 00:00:00 2001 From: martincostello Date: Thu, 11 Mar 2021 18:33:06 +0000 Subject: [PATCH 02/29] Update to .NET 6 preview 2 Update to preview 2 of .NET 6. --- Directory.Packages.props | 14 +++++++------- global.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index da243997..a137af20 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -7,7 +7,7 @@ - + @@ -28,15 +28,15 @@ - - - + + + - - - + + + diff --git a/global.json b/global.json index 25408d36..646a24bf 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "6.0.100-preview.1.21103.13", + "version": "6.0.100-preview.2.21155.3", "allowPrerelease": false, "rollForward": "latestMajor" } From e62d0cb967b2098a1449f3ad059e0039c66c354c Mon Sep 17 00:00:00 2001 From: martincostello Date: Thu, 8 Apr 2021 21:33:55 +0100 Subject: [PATCH 03/29] Update to .NET 6 preview 3 Update to preview 3 of .NET 6. --- Directory.Build.props | 2 ++ Directory.Packages.props | 14 +++++++------- global.json | 2 +- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index ee76787b..6e97d8d7 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -24,6 +24,8 @@ en-US $(NoWarn);CA1054;CA2234 $(NoWarn);SA0001 + + $(NoWarn);SA1518;SA1633 enable Apache-2.0 https://github.com/martincostello/sqllocaldb diff --git a/Directory.Packages.props b/Directory.Packages.props index a137af20..af8bd9bb 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -7,7 +7,7 @@ - + @@ -28,15 +28,15 @@ - - - + + + - - - + + + diff --git a/global.json b/global.json index 646a24bf..a7b2be52 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "6.0.100-preview.2.21155.3", + "version": "6.0.100-preview.3.21202.5", "allowPrerelease": false, "rollForward": "latestMajor" } From a72208d38616fbc0ccb4c9ff1e1fe4bfa7e35ea4 Mon Sep 17 00:00:00 2001 From: martincostello Date: Tue, 25 May 2021 14:21:59 +0100 Subject: [PATCH 04/29] Update to .NET 6 preview 4 Update to preview 4 of .NET 6. --- Directory.Packages.props | 14 +++++++------- global.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index af8bd9bb..68deb27b 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -7,7 +7,7 @@ - + @@ -28,15 +28,15 @@ - - - + + + - - - + + + diff --git a/global.json b/global.json index a7b2be52..a9370cf5 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "6.0.100-preview.3.21202.5", + "version": "6.0.100-preview.4.21262.10", "allowPrerelease": false, "rollForward": "latestMajor" } From a285e8948f9df9b25ef60f90421e1c8c6138dd5d Mon Sep 17 00:00:00 2001 From: Martin Costello Date: Tue, 25 May 2021 15:05:08 +0100 Subject: [PATCH 05/29] Use correct .NET 6 preview 4 SDK Use the official build of the .NET 6 preview 4 SDK. --- global.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global.json b/global.json index a9370cf5..f4ad1099 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "6.0.100-preview.4.21262.10", + "version": "6.0.100-preview.4.21255.9", "allowPrerelease": false, "rollForward": "latestMajor" } From 6560c9842adf7b4c2a1dd8f89138ce8d5937345d Mon Sep 17 00:00:00 2001 From: martincostello Date: Thu, 17 Jun 2021 16:27:01 +0100 Subject: [PATCH 06/29] Update to .NET 6 preview 5 Update to preview 5 of .NET 6. --- Directory.Build.props | 2 -- Directory.Packages.props | 14 +++++++------- global.json | 2 +- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 6e97d8d7..ee76787b 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -24,8 +24,6 @@ en-US $(NoWarn);CA1054;CA2234 $(NoWarn);SA0001 - - $(NoWarn);SA1518;SA1633 enable Apache-2.0 https://github.com/martincostello/sqllocaldb diff --git a/Directory.Packages.props b/Directory.Packages.props index 68deb27b..8550c933 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -7,7 +7,7 @@ - + @@ -28,15 +28,15 @@ - - - + + + - - - + + + diff --git a/global.json b/global.json index f4ad1099..de80aabd 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "6.0.100-preview.4.21255.9", + "version": "6.0.100-preview.5.21302.13", "allowPrerelease": false, "rollForward": "latestMajor" } From dd6ac173840794b655d27611337d9db6223c3d80 Mon Sep 17 00:00:00 2001 From: martincostello Date: Sun, 20 Jun 2021 14:55:14 +0100 Subject: [PATCH 07/29] Use CreateAsyncScope() Use the new CreateAsyncScope() method instead of CreateScope(). Use async disposable for SqlConnection. --- .vsconfig | 2 +- tests/SqlLocalDb.Tests/Examples.cs | 15 ++++++++------- tests/SqlLocalDb.Tests/SqlLocalDbApiTests.cs | 2 +- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/.vsconfig b/.vsconfig index 46304174..ab008c3f 100644 --- a/.vsconfig +++ b/.vsconfig @@ -3,7 +3,7 @@ "components": [ "Microsoft.VisualStudio.Component.CoreEditor", "Microsoft.VisualStudio.Workload.CoreEditor", - "Microsoft.NetCore.Component.Runtime.5.0", + "Microsoft.NetCore.Component.Runtime.6.0", "Microsoft.NetCore.Component.SDK", "Microsoft.VisualStudio.Component.Roslyn.Compiler", "Microsoft.VisualStudio.Component.Roslyn.LanguageServices" diff --git a/tests/SqlLocalDb.Tests/Examples.cs b/tests/SqlLocalDb.Tests/Examples.cs index 733b6f33..6a94d75f 100644 --- a/tests/SqlLocalDb.Tests/Examples.cs +++ b/tests/SqlLocalDb.Tests/Examples.cs @@ -2,6 +2,7 @@ // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. using System; +using System.Threading.Tasks; using Microsoft.Data.SqlClient; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -22,7 +23,7 @@ public Examples(ITestOutputHelper outputHelper) private ITestOutputHelper OutputHelper { get; } [WindowsOnlyFact] - public void Create_A_Sql_LocalDB_Instance() + public async Task Create_A_Sql_LocalDB_Instance() { using (var localDB = new SqlLocalDbApi(OutputHelper.ToLoggerFactory())) { @@ -34,7 +35,7 @@ public void Create_A_Sql_LocalDB_Instance() manager.Start(); } - using (SqlConnection connection = instance.CreateConnection()) + await using (SqlConnection connection = instance.CreateConnection()) { connection.Open(); @@ -46,13 +47,13 @@ public void Create_A_Sql_LocalDB_Instance() } [WindowsOnlyFact] - public void Create_A_Temporary_Sql_LocalDB_Instance() + public async Task Create_A_Temporary_Sql_LocalDB_Instance() { using (var localDB = new SqlLocalDbApi(OutputHelper.ToLoggerFactory())) { using (TemporarySqlLocalDbInstance instance = localDB.CreateTemporaryInstance(deleteFiles: true)) { - using (var connection = new SqlConnection(instance.ConnectionString)) + await using (var connection = new SqlConnection(instance.ConnectionString)) { connection.Open(); @@ -63,7 +64,7 @@ public void Create_A_Temporary_Sql_LocalDB_Instance() } [WindowsOnlyFact] - public void Use_With_Dependency_Injection() + public async Task Use_With_Dependency_Injection() { // Register with SQL LocalDB services var services = new ServiceCollection() @@ -72,7 +73,7 @@ public void Use_With_Dependency_Injection() IServiceProvider serviceProvider = services.BuildServiceProvider(); - using (IServiceScope scope = serviceProvider.CreateScope()) + await using (AsyncServiceScope scope = serviceProvider.CreateAsyncScope()) { ISqlLocalDbApi localDB = scope!.ServiceProvider!.GetRequiredService(); ISqlLocalDbInstanceInfo instance = localDB!.GetDefaultInstance(); @@ -83,7 +84,7 @@ public void Use_With_Dependency_Injection() manager.Start(); } - using (SqlConnection connection = instance.CreateConnection()) + await using (SqlConnection connection = instance.CreateConnection()) { connection.Open(); diff --git a/tests/SqlLocalDb.Tests/SqlLocalDbApiTests.cs b/tests/SqlLocalDb.Tests/SqlLocalDbApiTests.cs index 3b1ee7f9..40f0b56a 100644 --- a/tests/SqlLocalDb.Tests/SqlLocalDbApiTests.cs +++ b/tests/SqlLocalDb.Tests/SqlLocalDbApiTests.cs @@ -290,7 +290,7 @@ public async Task Can_Manage_SqlLocalDB_Instances() var builder = new SqlConnectionStringBuilder() { DataSource = namedPipe }; - using (var connection = new SqlConnection(builder.ConnectionString)) + await using (var connection = new SqlConnection(builder.ConnectionString)) { await connection.OpenAsync(); } From 1ac2b1e8e248c0af3b1e467844e88aac959b0167 Mon Sep 17 00:00:00 2001 From: martincostello Date: Sat, 26 Jun 2021 09:32:04 +0100 Subject: [PATCH 08/29] Add NuGet package validation Add new NuGet package validation SDK. See https://devblogs.microsoft.com/dotnet/package-validation/. --- Directory.Packages.props | 1 + src/SqlLocalDb/MartinCostello.SqlLocalDb.csproj | 2 ++ 2 files changed, 3 insertions(+) diff --git a/Directory.Packages.props b/Directory.Packages.props index 8550c933..ba565547 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -7,6 +7,7 @@ + diff --git a/src/SqlLocalDb/MartinCostello.SqlLocalDb.csproj b/src/SqlLocalDb/MartinCostello.SqlLocalDb.csproj index 899732bb..c77cced6 100644 --- a/src/SqlLocalDb/MartinCostello.SqlLocalDb.csproj +++ b/src/SqlLocalDb/MartinCostello.SqlLocalDb.csproj @@ -1,4 +1,5 @@ + SQL LocalDB Wrapper A .NET assembly providing interop with the SQL LocalDB native API from managed code using .NET APIs. @@ -6,6 +7,7 @@ $(NoWarn);CA2235 Library MartinCostello.SqlLocalDb + 3.0.0 MartinCostello.SqlLocalDb $(Description) netstandard2.0;net6.0 From 005af1aaec390d1aad79c1aed5ecef452e9da55f Mon Sep 17 00:00:00 2001 From: martincostello Date: Sat, 26 Jun 2021 09:50:24 +0100 Subject: [PATCH 09/29] Fix package validation Add workaround for bug in package validation targets. --- build.ps1 | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/build.ps1 b/build.ps1 index cbcb6166..a75df894 100755 --- a/build.ps1 +++ b/build.ps1 @@ -101,11 +101,14 @@ function DotNetBuild { function DotNetPack { param([string]$Project) + # HACK Workaround for https://github.com/dotnet/sdk/pull/18191 + $PackageOutputPath = ((Join-Path $OutputPath "packages") + [IO.Path]::DirectorySeparatorChar) + if ($VersionSuffix) { - & $dotnet pack $Project --output (Join-Path $OutputPath "packages") --configuration $Configuration --version-suffix "$VersionSuffix" --include-symbols --include-source + & $dotnet pack $Project --output $PackageOutputPath --configuration $Configuration --version-suffix "$VersionSuffix" --include-symbols --include-source } else { - & $dotnet pack $Project --output (Join-Path $OutputPath "packages") --configuration $Configuration --include-symbols --include-source + & $dotnet pack $Project --output $PackageOutputPath --configuration $Configuration --include-symbols --include-source } if ($LASTEXITCODE -ne 0) { throw "dotnet pack failed with exit code $LASTEXITCODE" From 29fcec1add8376dc82d0bd706ba505419b389cb1 Mon Sep 17 00:00:00 2001 From: martincostello Date: Wed, 14 Jul 2021 16:57:31 +0100 Subject: [PATCH 10/29] Update to .NET 6 preview 6 Update to preview 6 of .NET 6. --- CHANGELOG | 5 +++++ Directory.Build.props | 2 +- Directory.Packages.props | 15 +++++++-------- global.json | 2 +- src/SqlLocalDb/Interop/SafeLibraryHandle.cs | 4 ++-- src/SqlLocalDb/MartinCostello.SqlLocalDb.csproj | 4 +++- 6 files changed, 19 insertions(+), 13 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 92286f93..335efcb2 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -200,3 +200,8 @@ Added overloads to support specifying the name of the Initial Catalog using the * Publish symbol packages to NuGet.org. * Use GitHub Actions for CI. * Prepare for .NET 6. + +# SqlLocalDb v3.1.0 + +## Added + * Add `net6.0` Target Framework Moniker. diff --git a/Directory.Build.props b/Directory.Build.props index ee76787b..bf697702 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -37,7 +37,7 @@ true snupkg true - 3.0.2 + 3.1.0 beta$([System.Convert]::ToInt32(`$(GITHUB_RUN_NUMBER)`).ToString(`0000`)) $(GITHUB_REF.Replace('refs/tags/v', '')) diff --git a/Directory.Packages.props b/Directory.Packages.props index ba565547..f8b7d07c 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -7,8 +7,8 @@ - - + + @@ -29,15 +29,14 @@ - - - + + - - - + + + diff --git a/global.json b/global.json index de80aabd..41d80fcc 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "6.0.100-preview.5.21302.13", + "version": "6.0.100-preview.6.21355.2", "allowPrerelease": false, "rollForward": "latestMajor" } diff --git a/src/SqlLocalDb/Interop/SafeLibraryHandle.cs b/src/SqlLocalDb/Interop/SafeLibraryHandle.cs index 3a926061..7d466770 100644 --- a/src/SqlLocalDb/Interop/SafeLibraryHandle.cs +++ b/src/SqlLocalDb/Interop/SafeLibraryHandle.cs @@ -11,9 +11,9 @@ namespace MartinCostello.SqlLocalDb.Interop internal sealed class SafeLibraryHandle : SafeHandleZeroOrMinusOneIsInvalid { /// - /// Prevents a default instance of the class from being created. + /// Initializes a new instance of the class. /// - private SafeLibraryHandle() + public SafeLibraryHandle() : base(true) { } diff --git a/src/SqlLocalDb/MartinCostello.SqlLocalDb.csproj b/src/SqlLocalDb/MartinCostello.SqlLocalDb.csproj index c77cced6..746ff5ae 100644 --- a/src/SqlLocalDb/MartinCostello.SqlLocalDb.csproj +++ b/src/SqlLocalDb/MartinCostello.SqlLocalDb.csproj @@ -1,5 +1,5 @@ - + SQL LocalDB Wrapper A .NET assembly providing interop with the SQL LocalDB native API from managed code using .NET APIs. @@ -21,6 +21,8 @@ + + From e8674dfee356c3db789f85bbea570f8da640c211 Mon Sep 17 00:00:00 2001 From: martincostello Date: Wed, 11 Aug 2021 12:19:24 +0100 Subject: [PATCH 11/29] Update to .NET 6 preview 7 Update to preview 7 of .NET 6. --- Directory.Packages.props | 14 +++++++------- build.ps1 | 3 +-- global.json | 2 +- src/SqlLocalDb/MartinCostello.SqlLocalDb.csproj | 2 +- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index f8b7d07c..d5c4ba83 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -7,8 +7,8 @@ - - + + @@ -29,14 +29,14 @@ - - + + - - - + + + diff --git a/build.ps1 b/build.ps1 index a75df894..af52ba59 100755 --- a/build.ps1 +++ b/build.ps1 @@ -101,8 +101,7 @@ function DotNetBuild { function DotNetPack { param([string]$Project) - # HACK Workaround for https://github.com/dotnet/sdk/pull/18191 - $PackageOutputPath = ((Join-Path $OutputPath "packages") + [IO.Path]::DirectorySeparatorChar) + $PackageOutputPath = (Join-Path $OutputPath "packages") if ($VersionSuffix) { & $dotnet pack $Project --output $PackageOutputPath --configuration $Configuration --version-suffix "$VersionSuffix" --include-symbols --include-source diff --git a/global.json b/global.json index 41d80fcc..9fea25b4 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "6.0.100-preview.6.21355.2", + "version": "6.0.100-preview.7.21379.14", "allowPrerelease": false, "rollForward": "latestMajor" } diff --git a/src/SqlLocalDb/MartinCostello.SqlLocalDb.csproj b/src/SqlLocalDb/MartinCostello.SqlLocalDb.csproj index 746ff5ae..e2ae7b8a 100644 --- a/src/SqlLocalDb/MartinCostello.SqlLocalDb.csproj +++ b/src/SqlLocalDb/MartinCostello.SqlLocalDb.csproj @@ -1,5 +1,5 @@ - + SQL LocalDB Wrapper A .NET assembly providing interop with the SQL LocalDB native API from managed code using .NET APIs. From 44e324d6f71e9f96213a36221acf28c29fec624e Mon Sep 17 00:00:00 2001 From: martincostello Date: Sun, 22 Aug 2021 09:57:58 +0100 Subject: [PATCH 12/29] Update to .NET 6 RC1 daily build Update to a daily build of release candidate 1 of .NET 6. --- Directory.Packages.props | 12 ++++++------ NuGet.config | 1 + global.json | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index d5c4ba83..9c4fde60 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -8,7 +8,7 @@ - + @@ -29,14 +29,14 @@ - - + + - - - + + + diff --git a/NuGet.config b/NuGet.config index 21cb6efa..31d18de7 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,6 +1,7 @@ + diff --git a/global.json b/global.json index 9fea25b4..a46c8f7e 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "6.0.100-preview.7.21379.14", + "version": "6.0.100-rc.1.21420.39", "allowPrerelease": false, "rollForward": "latestMajor" } From c0b14f899b96b38762e9fef9c957cbfb3c9ee575 Mon Sep 17 00:00:00 2001 From: martincostello Date: Sun, 22 Aug 2021 10:05:50 +0100 Subject: [PATCH 13/29] Use implicit using statements Use implicit using statements and remove redundant using statements. --- Directory.Build.props | 9 +++++++++ SqlLocalDb.sln | 4 ++-- samples/TodoApp.Tests/TodoApp.Tests.csproj | 1 + src/SqlLocalDb/ISqlLocalDbInstanceInfo.cs | 4 +--- src/SqlLocalDb/ISqlLocalDbInstanceInfoExtensions.cs | 1 - src/SqlLocalDb/ISqlLocalDbInstanceManagerExtensions.cs | 3 +-- src/SqlLocalDb/ISqlLocalDbVersionInfo.cs | 4 +--- src/SqlLocalDb/Interop/IRegistryKey.cs | 4 +--- src/SqlLocalDb/Interop/LocalDbInstanceApi.cs | 3 --- src/SqlLocalDb/Interop/LocalDbInstanceInfo.cs | 3 +-- src/SqlLocalDb/Interop/LocalDbVersionInfo.cs | 3 +-- src/SqlLocalDb/Interop/NativeMethods.cs | 3 +-- src/SqlLocalDb/Interop/WindowsRegistryKey.cs | 3 +-- src/SqlLocalDb/SRHelper.cs | 4 +--- src/SqlLocalDb/SqlLocalDbApi.cs | 5 ----- src/SqlLocalDb/SqlLocalDbException.cs | 3 +-- src/SqlLocalDb/SqlLocalDbInstanceInfo.cs | 1 - src/SqlLocalDb/SqlLocalDbInstanceManager.cs | 1 - src/SqlLocalDb/SqlLocalDbOptions.cs | 3 --- src/SqlLocalDb/SqlLocalDbServiceCollectionExtensions.cs | 1 - src/SqlLocalDb/SqlLocalDbVersionInfo.cs | 3 +-- src/SqlLocalDb/StopInstanceOptions.cs | 4 +--- src/SqlLocalDb/TemporarySqlLocalDbInstance.cs | 1 - src/TestApp/Program.cs | 3 --- tests/SqlLocalDb.Tests/DelayedMessageBus.cs | 2 -- tests/SqlLocalDb.Tests/EventIdsTests.cs | 2 -- tests/SqlLocalDb.Tests/Examples.cs | 3 --- tests/SqlLocalDb.Tests/ISqlLocalDbApiExtensionsTests.cs | 5 ----- .../ISqlLocalDbInstanceInfoExtensionsTests.cs | 3 --- .../ISqlLocalDbInstanceManagerExtensionsTests.cs | 5 ----- tests/SqlLocalDb.Tests/NotInParallelTests.cs | 6 ------ tests/SqlLocalDb.Tests/NotWindowsFactAttribute.cs | 5 +---- tests/SqlLocalDb.Tests/RetryFactDiscoverer.cs | 2 -- tests/SqlLocalDb.Tests/RetryTestCase.cs | 4 ---- tests/SqlLocalDb.Tests/RunAsAdminFactAttribute.cs | 2 -- tests/SqlLocalDb.Tests/SqlLocalDbApiTests.cs | 8 -------- tests/SqlLocalDb.Tests/SqlLocalDbExceptionTests.cs | 5 +---- tests/SqlLocalDb.Tests/SqlLocalDbInstanceInfoTests.cs | 3 --- tests/SqlLocalDb.Tests/SqlLocalDbInstanceManagerTests.cs | 4 ---- tests/SqlLocalDb.Tests/SqlLocalDbOptionsTests.cs | 7 +------ .../SqlLocalDbServiceCollectionExtensionsTests.cs | 3 --- tests/SqlLocalDb.Tests/SqlLocalDbVersionInfoTests.cs | 6 +----- tests/SqlLocalDb.Tests/WindowsCIOnlyFactAttribute.cs | 5 +---- tests/SqlLocalDb.Tests/WindowsOnlyFactAttribute.cs | 2 -- 44 files changed, 29 insertions(+), 127 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index bf697702..02af48cb 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -19,6 +19,7 @@ true false true + enable latest true en-US @@ -53,4 +54,12 @@ 80 40 + + + + + + + + diff --git a/SqlLocalDb.sln b/SqlLocalDb.sln index 7bde2446..0cc5e305 100644 --- a/SqlLocalDb.sln +++ b/SqlLocalDb.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.28922.388 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31612.314 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{E207A447-68A1-4D72-B24F-89FB7890AE12}" ProjectSection(SolutionItems) = preProject diff --git a/samples/TodoApp.Tests/TodoApp.Tests.csproj b/samples/TodoApp.Tests/TodoApp.Tests.csproj index 277b2c9d..31ef5ae1 100644 --- a/samples/TodoApp.Tests/TodoApp.Tests.csproj +++ b/samples/TodoApp.Tests/TodoApp.Tests.csproj @@ -11,6 +11,7 @@ + diff --git a/src/SqlLocalDb/ISqlLocalDbInstanceInfo.cs b/src/SqlLocalDb/ISqlLocalDbInstanceInfo.cs index b96cfd61..5f645659 100644 --- a/src/SqlLocalDb/ISqlLocalDbInstanceInfo.cs +++ b/src/SqlLocalDb/ISqlLocalDbInstanceInfo.cs @@ -1,8 +1,6 @@ -// Copyright (c) Martin Costello, 2012-2018. All rights reserved. +// Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -using System; - namespace MartinCostello.SqlLocalDb { /// diff --git a/src/SqlLocalDb/ISqlLocalDbInstanceInfoExtensions.cs b/src/SqlLocalDb/ISqlLocalDbInstanceInfoExtensions.cs index 33a52cde..49c993b0 100644 --- a/src/SqlLocalDb/ISqlLocalDbInstanceInfoExtensions.cs +++ b/src/SqlLocalDb/ISqlLocalDbInstanceInfoExtensions.cs @@ -1,7 +1,6 @@ // Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -using System; using System.ComponentModel; using Microsoft.Data.SqlClient; diff --git a/src/SqlLocalDb/ISqlLocalDbInstanceManagerExtensions.cs b/src/SqlLocalDb/ISqlLocalDbInstanceManagerExtensions.cs index 46cde088..0f2cccdb 100644 --- a/src/SqlLocalDb/ISqlLocalDbInstanceManagerExtensions.cs +++ b/src/SqlLocalDb/ISqlLocalDbInstanceManagerExtensions.cs @@ -1,7 +1,6 @@ -// Copyright (c) Martin Costello, 2012-2018. All rights reserved. +// Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -using System; using System.ComponentModel; using Microsoft.Data.SqlClient; diff --git a/src/SqlLocalDb/ISqlLocalDbVersionInfo.cs b/src/SqlLocalDb/ISqlLocalDbVersionInfo.cs index 970f0049..c8a9367c 100644 --- a/src/SqlLocalDb/ISqlLocalDbVersionInfo.cs +++ b/src/SqlLocalDb/ISqlLocalDbVersionInfo.cs @@ -1,8 +1,6 @@ -// Copyright (c) Martin Costello, 2012-2018. All rights reserved. +// Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -using System; - namespace MartinCostello.SqlLocalDb { /// diff --git a/src/SqlLocalDb/Interop/IRegistryKey.cs b/src/SqlLocalDb/Interop/IRegistryKey.cs index ea9804c7..cbe3e399 100644 --- a/src/SqlLocalDb/Interop/IRegistryKey.cs +++ b/src/SqlLocalDb/Interop/IRegistryKey.cs @@ -1,8 +1,6 @@ -// Copyright (c) Martin Costello, 2012-2018. All rights reserved. +// Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -using System; - namespace MartinCostello.SqlLocalDb.Interop { /// diff --git a/src/SqlLocalDb/Interop/LocalDbInstanceApi.cs b/src/SqlLocalDb/Interop/LocalDbInstanceApi.cs index 201ffd16..099b6aba 100644 --- a/src/SqlLocalDb/Interop/LocalDbInstanceApi.cs +++ b/src/SqlLocalDb/Interop/LocalDbInstanceApi.cs @@ -1,10 +1,7 @@ // Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -using System; using System.Diagnostics; -using System.Globalization; -using System.IO; using System.Runtime.InteropServices; using System.Text; using Microsoft.Extensions.Logging; diff --git a/src/SqlLocalDb/Interop/LocalDbInstanceInfo.cs b/src/SqlLocalDb/Interop/LocalDbInstanceInfo.cs index f4023003..15e17d92 100644 --- a/src/SqlLocalDb/Interop/LocalDbInstanceInfo.cs +++ b/src/SqlLocalDb/Interop/LocalDbInstanceInfo.cs @@ -1,7 +1,6 @@ -// Copyright (c) Martin Costello, 2012-2018. All rights reserved. +// Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -using System; using System.Diagnostics; using System.Runtime.InteropServices; diff --git a/src/SqlLocalDb/Interop/LocalDbVersionInfo.cs b/src/SqlLocalDb/Interop/LocalDbVersionInfo.cs index 912d70ca..0cd4ea8c 100644 --- a/src/SqlLocalDb/Interop/LocalDbVersionInfo.cs +++ b/src/SqlLocalDb/Interop/LocalDbVersionInfo.cs @@ -1,7 +1,6 @@ -// Copyright (c) Martin Costello, 2012-2018. All rights reserved. +// Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -using System; using System.Diagnostics; using System.Runtime.InteropServices; diff --git a/src/SqlLocalDb/Interop/NativeMethods.cs b/src/SqlLocalDb/Interop/NativeMethods.cs index 3acf21a9..0abf2927 100644 --- a/src/SqlLocalDb/Interop/NativeMethods.cs +++ b/src/SqlLocalDb/Interop/NativeMethods.cs @@ -1,7 +1,6 @@ -// Copyright (c) Martin Costello, 2012-2018. All rights reserved. +// Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -using System; using System.Runtime.InteropServices; namespace MartinCostello.SqlLocalDb.Interop diff --git a/src/SqlLocalDb/Interop/WindowsRegistryKey.cs b/src/SqlLocalDb/Interop/WindowsRegistryKey.cs index 0d810775..f1cafc20 100644 --- a/src/SqlLocalDb/Interop/WindowsRegistryKey.cs +++ b/src/SqlLocalDb/Interop/WindowsRegistryKey.cs @@ -1,7 +1,6 @@ -// Copyright (c) Martin Costello, 2012-2018. All rights reserved. +// Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -using System; using System.Diagnostics; using Microsoft.Win32; diff --git a/src/SqlLocalDb/SRHelper.cs b/src/SqlLocalDb/SRHelper.cs index 1970798a..28b847a0 100644 --- a/src/SqlLocalDb/SRHelper.cs +++ b/src/SqlLocalDb/SRHelper.cs @@ -1,8 +1,6 @@ -// Copyright (c) Martin Costello, 2012-2018. All rights reserved. +// Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -using System; - namespace MartinCostello.SqlLocalDb { /// diff --git a/src/SqlLocalDb/SqlLocalDbApi.cs b/src/SqlLocalDb/SqlLocalDbApi.cs index 407dff16..1be9abea 100644 --- a/src/SqlLocalDb/SqlLocalDbApi.cs +++ b/src/SqlLocalDb/SqlLocalDbApi.cs @@ -1,12 +1,7 @@ // Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -using System; -using System.Collections.Generic; using System.Diagnostics; -using System.Globalization; -using System.IO; -using System.Linq; using System.Runtime.InteropServices; using System.Security.Principal; using System.Text; diff --git a/src/SqlLocalDb/SqlLocalDbException.cs b/src/SqlLocalDb/SqlLocalDbException.cs index 1a2cdabc..7c2b764d 100644 --- a/src/SqlLocalDb/SqlLocalDbException.cs +++ b/src/SqlLocalDb/SqlLocalDbException.cs @@ -1,7 +1,6 @@ -// Copyright (c) Martin Costello, 2012-2018. All rights reserved. +// Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -using System; using System.Data.Common; using System.Runtime.Serialization; diff --git a/src/SqlLocalDb/SqlLocalDbInstanceInfo.cs b/src/SqlLocalDb/SqlLocalDbInstanceInfo.cs index 6074775b..af79fcdb 100644 --- a/src/SqlLocalDb/SqlLocalDbInstanceInfo.cs +++ b/src/SqlLocalDb/SqlLocalDbInstanceInfo.cs @@ -1,7 +1,6 @@ // Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -using System; using System.Diagnostics; namespace MartinCostello.SqlLocalDb diff --git a/src/SqlLocalDb/SqlLocalDbInstanceManager.cs b/src/SqlLocalDb/SqlLocalDbInstanceManager.cs index 2daceeeb..3292b7b9 100644 --- a/src/SqlLocalDb/SqlLocalDbInstanceManager.cs +++ b/src/SqlLocalDb/SqlLocalDbInstanceManager.cs @@ -1,7 +1,6 @@ // Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -using System; using System.Diagnostics; namespace MartinCostello.SqlLocalDb diff --git a/src/SqlLocalDb/SqlLocalDbOptions.cs b/src/SqlLocalDb/SqlLocalDbOptions.cs index 72f5c663..bbe8c13b 100644 --- a/src/SqlLocalDb/SqlLocalDbOptions.cs +++ b/src/SqlLocalDb/SqlLocalDbOptions.cs @@ -1,9 +1,6 @@ // Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -using System; -using System.Globalization; - namespace MartinCostello.SqlLocalDb { /// diff --git a/src/SqlLocalDb/SqlLocalDbServiceCollectionExtensions.cs b/src/SqlLocalDb/SqlLocalDbServiceCollectionExtensions.cs index c10b15d4..9c7dde28 100644 --- a/src/SqlLocalDb/SqlLocalDbServiceCollectionExtensions.cs +++ b/src/SqlLocalDb/SqlLocalDbServiceCollectionExtensions.cs @@ -1,7 +1,6 @@ // Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -using System; using System.ComponentModel; using MartinCostello.SqlLocalDb; using Microsoft.Extensions.DependencyInjection.Extensions; diff --git a/src/SqlLocalDb/SqlLocalDbVersionInfo.cs b/src/SqlLocalDb/SqlLocalDbVersionInfo.cs index 377b0499..e39888cb 100644 --- a/src/SqlLocalDb/SqlLocalDbVersionInfo.cs +++ b/src/SqlLocalDb/SqlLocalDbVersionInfo.cs @@ -1,7 +1,6 @@ -// Copyright (c) Martin Costello, 2012-2018. All rights reserved. +// Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -using System; using System.Diagnostics; namespace MartinCostello.SqlLocalDb diff --git a/src/SqlLocalDb/StopInstanceOptions.cs b/src/SqlLocalDb/StopInstanceOptions.cs index c0754df9..4c5539f6 100644 --- a/src/SqlLocalDb/StopInstanceOptions.cs +++ b/src/SqlLocalDb/StopInstanceOptions.cs @@ -1,8 +1,6 @@ -// Copyright (c) Martin Costello, 2012-2018. All rights reserved. +// Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -using System; - namespace MartinCostello.SqlLocalDb { /// diff --git a/src/SqlLocalDb/TemporarySqlLocalDbInstance.cs b/src/SqlLocalDb/TemporarySqlLocalDbInstance.cs index abaeca1e..88a1000f 100644 --- a/src/SqlLocalDb/TemporarySqlLocalDbInstance.cs +++ b/src/SqlLocalDb/TemporarySqlLocalDbInstance.cs @@ -1,7 +1,6 @@ // Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -using System; using Microsoft.Extensions.Logging; namespace MartinCostello.SqlLocalDb diff --git a/src/TestApp/Program.cs b/src/TestApp/Program.cs index df5e63a9..663beef7 100644 --- a/src/TestApp/Program.cs +++ b/src/TestApp/Program.cs @@ -1,12 +1,9 @@ // Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -using System; -using System.Collections.Generic; using System.Reflection; using System.Runtime.InteropServices; using System.Security.Principal; -using System.Threading.Tasks; using Microsoft.Data.SqlClient; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; diff --git a/tests/SqlLocalDb.Tests/DelayedMessageBus.cs b/tests/SqlLocalDb.Tests/DelayedMessageBus.cs index 53b1f68d..2a088be7 100644 --- a/tests/SqlLocalDb.Tests/DelayedMessageBus.cs +++ b/tests/SqlLocalDb.Tests/DelayedMessageBus.cs @@ -1,8 +1,6 @@ // Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -using System.Collections.Generic; -using Xunit.Abstractions; using Xunit.Sdk; namespace MartinCostello.SqlLocalDb diff --git a/tests/SqlLocalDb.Tests/EventIdsTests.cs b/tests/SqlLocalDb.Tests/EventIdsTests.cs index d3a40415..02150804 100644 --- a/tests/SqlLocalDb.Tests/EventIdsTests.cs +++ b/tests/SqlLocalDb.Tests/EventIdsTests.cs @@ -3,8 +3,6 @@ using System.Reflection; using Microsoft.Extensions.Logging; -using Shouldly; -using Xunit; namespace MartinCostello.SqlLocalDb { diff --git a/tests/SqlLocalDb.Tests/Examples.cs b/tests/SqlLocalDb.Tests/Examples.cs index 6a94d75f..f854632b 100644 --- a/tests/SqlLocalDb.Tests/Examples.cs +++ b/tests/SqlLocalDb.Tests/Examples.cs @@ -1,12 +1,9 @@ // Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -using System; -using System.Threading.Tasks; using Microsoft.Data.SqlClient; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using Xunit.Abstractions; namespace MartinCostello.SqlLocalDb { diff --git a/tests/SqlLocalDb.Tests/ISqlLocalDbApiExtensionsTests.cs b/tests/SqlLocalDb.Tests/ISqlLocalDbApiExtensionsTests.cs index 0a7ccccf..053cf6ba 100644 --- a/tests/SqlLocalDb.Tests/ISqlLocalDbApiExtensionsTests.cs +++ b/tests/SqlLocalDb.Tests/ISqlLocalDbApiExtensionsTests.cs @@ -1,13 +1,8 @@ // Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -using System; -using System.Collections.Generic; using Microsoft.Extensions.Logging; using Moq; -using Shouldly; -using Xunit; -using Xunit.Abstractions; namespace MartinCostello.SqlLocalDb { diff --git a/tests/SqlLocalDb.Tests/ISqlLocalDbInstanceInfoExtensionsTests.cs b/tests/SqlLocalDb.Tests/ISqlLocalDbInstanceInfoExtensionsTests.cs index da28b57f..53dd3bf3 100644 --- a/tests/SqlLocalDb.Tests/ISqlLocalDbInstanceInfoExtensionsTests.cs +++ b/tests/SqlLocalDb.Tests/ISqlLocalDbInstanceInfoExtensionsTests.cs @@ -1,11 +1,8 @@ // Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -using System; using Microsoft.Data.SqlClient; using Moq; -using Shouldly; -using Xunit; namespace MartinCostello.SqlLocalDb { diff --git a/tests/SqlLocalDb.Tests/ISqlLocalDbInstanceManagerExtensionsTests.cs b/tests/SqlLocalDb.Tests/ISqlLocalDbInstanceManagerExtensionsTests.cs index 6edf0746..caf741d7 100644 --- a/tests/SqlLocalDb.Tests/ISqlLocalDbInstanceManagerExtensionsTests.cs +++ b/tests/SqlLocalDb.Tests/ISqlLocalDbInstanceManagerExtensionsTests.cs @@ -1,14 +1,9 @@ // Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -using System; using System.Data; -using System.Threading.Tasks; using Microsoft.Data.SqlClient; using Microsoft.Extensions.Logging; -using Shouldly; -using Xunit; -using Xunit.Abstractions; namespace MartinCostello.SqlLocalDb { diff --git a/tests/SqlLocalDb.Tests/NotInParallelTests.cs b/tests/SqlLocalDb.Tests/NotInParallelTests.cs index 4a4f9982..7d91a9b7 100644 --- a/tests/SqlLocalDb.Tests/NotInParallelTests.cs +++ b/tests/SqlLocalDb.Tests/NotInParallelTests.cs @@ -1,13 +1,7 @@ // Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -using System; -using System.Collections.Generic; -using System.Linq; using Microsoft.Extensions.Logging; -using Shouldly; -using Xunit; -using Xunit.Abstractions; namespace MartinCostello.SqlLocalDb { diff --git a/tests/SqlLocalDb.Tests/NotWindowsFactAttribute.cs b/tests/SqlLocalDb.Tests/NotWindowsFactAttribute.cs index ffb7c4a4..427abe6a 100644 --- a/tests/SqlLocalDb.Tests/NotWindowsFactAttribute.cs +++ b/tests/SqlLocalDb.Tests/NotWindowsFactAttribute.cs @@ -1,9 +1,6 @@ -// Copyright (c) Martin Costello, 2012-2018. All rights reserved. +// Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -using System; -using Xunit; - namespace MartinCostello.SqlLocalDb { /// diff --git a/tests/SqlLocalDb.Tests/RetryFactDiscoverer.cs b/tests/SqlLocalDb.Tests/RetryFactDiscoverer.cs index 56d774da..bee0af15 100644 --- a/tests/SqlLocalDb.Tests/RetryFactDiscoverer.cs +++ b/tests/SqlLocalDb.Tests/RetryFactDiscoverer.cs @@ -1,8 +1,6 @@ // Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -using System.Collections.Generic; -using Xunit.Abstractions; using Xunit.Sdk; namespace MartinCostello.SqlLocalDb diff --git a/tests/SqlLocalDb.Tests/RetryTestCase.cs b/tests/SqlLocalDb.Tests/RetryTestCase.cs index 34e26840..b9fc5ece 100644 --- a/tests/SqlLocalDb.Tests/RetryTestCase.cs +++ b/tests/SqlLocalDb.Tests/RetryTestCase.cs @@ -1,11 +1,7 @@ // Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -using System; using System.ComponentModel; -using System.Threading; -using System.Threading.Tasks; -using Xunit.Abstractions; using Xunit.Sdk; namespace MartinCostello.SqlLocalDb diff --git a/tests/SqlLocalDb.Tests/RunAsAdminFactAttribute.cs b/tests/SqlLocalDb.Tests/RunAsAdminFactAttribute.cs index c7f3e41d..5f6d7930 100644 --- a/tests/SqlLocalDb.Tests/RunAsAdminFactAttribute.cs +++ b/tests/SqlLocalDb.Tests/RunAsAdminFactAttribute.cs @@ -1,9 +1,7 @@ // Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -using System; using System.Security.Principal; -using Xunit; using Xunit.Sdk; namespace MartinCostello.SqlLocalDb diff --git a/tests/SqlLocalDb.Tests/SqlLocalDbApiTests.cs b/tests/SqlLocalDb.Tests/SqlLocalDbApiTests.cs index 40f0b56a..4cf02f5a 100644 --- a/tests/SqlLocalDb.Tests/SqlLocalDbApiTests.cs +++ b/tests/SqlLocalDb.Tests/SqlLocalDbApiTests.cs @@ -1,17 +1,9 @@ // Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Threading.Tasks; using Microsoft.Data.SqlClient; using Microsoft.Extensions.Logging; using Moq; -using Shouldly; -using Xunit; -using Xunit.Abstractions; namespace MartinCostello.SqlLocalDb { diff --git a/tests/SqlLocalDb.Tests/SqlLocalDbExceptionTests.cs b/tests/SqlLocalDb.Tests/SqlLocalDbExceptionTests.cs index 291c34bc..f2384cd0 100644 --- a/tests/SqlLocalDb.Tests/SqlLocalDbExceptionTests.cs +++ b/tests/SqlLocalDb.Tests/SqlLocalDbExceptionTests.cs @@ -1,10 +1,7 @@ -// Copyright (c) Martin Costello, 2012-2018. All rights reserved. +// Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -using System; using System.Runtime.Serialization; -using Shouldly; -using Xunit; namespace MartinCostello.SqlLocalDb { diff --git a/tests/SqlLocalDb.Tests/SqlLocalDbInstanceInfoTests.cs b/tests/SqlLocalDb.Tests/SqlLocalDbInstanceInfoTests.cs index 3f400b0c..240e583f 100644 --- a/tests/SqlLocalDb.Tests/SqlLocalDbInstanceInfoTests.cs +++ b/tests/SqlLocalDb.Tests/SqlLocalDbInstanceInfoTests.cs @@ -1,10 +1,7 @@ // Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -using System; using Moq; -using Shouldly; -using Xunit; namespace MartinCostello.SqlLocalDb { diff --git a/tests/SqlLocalDb.Tests/SqlLocalDbInstanceManagerTests.cs b/tests/SqlLocalDb.Tests/SqlLocalDbInstanceManagerTests.cs index 50a442a1..1161884c 100644 --- a/tests/SqlLocalDb.Tests/SqlLocalDbInstanceManagerTests.cs +++ b/tests/SqlLocalDb.Tests/SqlLocalDbInstanceManagerTests.cs @@ -1,12 +1,8 @@ // Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -using System; using Microsoft.Extensions.Logging; using Moq; -using Shouldly; -using Xunit; -using Xunit.Abstractions; namespace MartinCostello.SqlLocalDb { diff --git a/tests/SqlLocalDb.Tests/SqlLocalDbOptionsTests.cs b/tests/SqlLocalDb.Tests/SqlLocalDbOptionsTests.cs index 8eb7150b..7df5659b 100644 --- a/tests/SqlLocalDb.Tests/SqlLocalDbOptionsTests.cs +++ b/tests/SqlLocalDb.Tests/SqlLocalDbOptionsTests.cs @@ -1,11 +1,6 @@ -// Copyright (c) Martin Costello, 2012-2018. All rights reserved. +// Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -using System; -using System.Globalization; -using Shouldly; -using Xunit; - namespace MartinCostello.SqlLocalDb { public static class SqlLocalDbOptionsTests diff --git a/tests/SqlLocalDb.Tests/SqlLocalDbServiceCollectionExtensionsTests.cs b/tests/SqlLocalDb.Tests/SqlLocalDbServiceCollectionExtensionsTests.cs index 3693aa9d..3925dcbd 100644 --- a/tests/SqlLocalDb.Tests/SqlLocalDbServiceCollectionExtensionsTests.cs +++ b/tests/SqlLocalDb.Tests/SqlLocalDbServiceCollectionExtensionsTests.cs @@ -1,11 +1,8 @@ // Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -using System; using Microsoft.Extensions.DependencyInjection; using Moq; -using Shouldly; -using Xunit; namespace MartinCostello.SqlLocalDb { diff --git a/tests/SqlLocalDb.Tests/SqlLocalDbVersionInfoTests.cs b/tests/SqlLocalDb.Tests/SqlLocalDbVersionInfoTests.cs index a3d59aa0..24def8a4 100644 --- a/tests/SqlLocalDb.Tests/SqlLocalDbVersionInfoTests.cs +++ b/tests/SqlLocalDb.Tests/SqlLocalDbVersionInfoTests.cs @@ -1,10 +1,6 @@ -// Copyright (c) Martin Costello, 2012-2018. All rights reserved. +// Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -using System; -using Shouldly; -using Xunit; - namespace MartinCostello.SqlLocalDb { public static class SqlLocalDbVersionInfoTests diff --git a/tests/SqlLocalDb.Tests/WindowsCIOnlyFactAttribute.cs b/tests/SqlLocalDb.Tests/WindowsCIOnlyFactAttribute.cs index b1243648..6884d08a 100644 --- a/tests/SqlLocalDb.Tests/WindowsCIOnlyFactAttribute.cs +++ b/tests/SqlLocalDb.Tests/WindowsCIOnlyFactAttribute.cs @@ -1,9 +1,6 @@ -// Copyright (c) Martin Costello, 2012-2018. All rights reserved. +// Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -using System; -using Xunit; - namespace MartinCostello.SqlLocalDb { /// diff --git a/tests/SqlLocalDb.Tests/WindowsOnlyFactAttribute.cs b/tests/SqlLocalDb.Tests/WindowsOnlyFactAttribute.cs index a5c53f92..d0a5bd68 100644 --- a/tests/SqlLocalDb.Tests/WindowsOnlyFactAttribute.cs +++ b/tests/SqlLocalDb.Tests/WindowsOnlyFactAttribute.cs @@ -1,8 +1,6 @@ // Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -using System; -using Xunit; using Xunit.Sdk; namespace MartinCostello.SqlLocalDb From a952aab3edf312a2b3c5ca6520a3da46b9750eb0 Mon Sep 17 00:00:00 2001 From: martincostello Date: Sun, 22 Aug 2021 10:19:43 +0100 Subject: [PATCH 14/29] Use file-scoped namespaces Switch to using file-scoped namespaces. Remove more redundant using statements. --- CommonAssemblyInfo.cs | 3 +- samples/TodoApp.Tests/TodoRepositoryTests.cs | 148 +- samples/TodoApp/Controllers/HomeController.cs | 117 +- samples/TodoApp/Data/ITodoRepository.cs | 96 +- samples/TodoApp/Data/TodoContext.cs | 31 +- samples/TodoApp/Data/TodoInitializer.cs | 27 +- samples/TodoApp/Data/TodoItem.cs | 41 +- samples/TodoApp/Data/TodoMigration.cs | 92 +- samples/TodoApp/Data/TodoRepository.cs | 146 +- samples/TodoApp/Models/ErrorViewModel.cs | 11 +- samples/TodoApp/Models/TodoItemModel.cs | 15 +- samples/TodoApp/Models/TodoListViewModel.cs | 9 +- samples/TodoApp/Program.cs | 22 +- samples/TodoApp/Services/ITodoService.cs | 93 +- samples/TodoApp/Services/TodoService.cs | 99 +- samples/TodoApp/Startup.cs | 116 +- src/SqlLocalDb/EventIds.cs | 593 ++-- src/SqlLocalDb/ILoggerExtensions.cs | 1433 +++++----- src/SqlLocalDb/ISqlLocalDbApi.cs | 270 +- src/SqlLocalDb/ISqlLocalDbApiAdapter.cs | 17 +- src/SqlLocalDb/ISqlLocalDbApiExtensions.cs | 307 ++- src/SqlLocalDb/ISqlLocalDbInstanceInfo.cs | 97 +- .../ISqlLocalDbInstanceInfoExtensions.cs | 187 +- src/SqlLocalDb/ISqlLocalDbInstanceManager.cs | 83 +- .../ISqlLocalDbInstanceManagerExtensions.cs | 71 +- src/SqlLocalDb/ISqlLocalDbVersionInfo.cs | 33 +- src/SqlLocalDb/Interop/IRegistry.cs | 25 +- src/SqlLocalDb/Interop/IRegistryKey.cs | 39 +- src/SqlLocalDb/Interop/LocalDbInstanceApi.cs | 1563 ++++++----- src/SqlLocalDb/Interop/LocalDbInstanceInfo.cs | 425 ++- src/SqlLocalDb/Interop/LocalDbVersionInfo.cs | 161 +- src/SqlLocalDb/Interop/NativeMethods.cs | 125 +- src/SqlLocalDb/Interop/SafeLibraryHandle.cs | 41 +- src/SqlLocalDb/Interop/WindowsRegistry.cs | 25 +- src/SqlLocalDb/Interop/WindowsRegistryKey.cs | 67 +- src/SqlLocalDb/SRHelper.cs | 47 +- src/SqlLocalDb/SqlLocalDbApi.cs | 2393 ++++++++--------- src/SqlLocalDb/SqlLocalDbErrors.cs | 873 +++--- src/SqlLocalDb/SqlLocalDbException.cs | 263 +- src/SqlLocalDb/SqlLocalDbInstanceInfo.cs | 133 +- src/SqlLocalDb/SqlLocalDbInstanceManager.cs | 267 +- src/SqlLocalDb/SqlLocalDbOptions.cs | 119 +- .../SqlLocalDbServiceCollectionExtensions.cs | 189 +- src/SqlLocalDb/SqlLocalDbVersionInfo.cs | 61 +- src/SqlLocalDb/StopInstanceOptions.cs | 35 +- src/SqlLocalDb/TemporarySqlLocalDbInstance.cs | 367 ++- src/TestApp/Program.cs | 263 +- tests/SqlLocalDb.Tests/DelayedMessageBus.cs | 43 +- tests/SqlLocalDb.Tests/EventIdsTests.cs | 141 +- tests/SqlLocalDb.Tests/Examples.cs | 115 +- .../ISqlLocalDbApiExtensionsTests.cs | 769 +++--- .../ISqlLocalDbInstanceInfoExtensionsTests.cs | 227 +- ...qlLocalDbInstanceManagerExtensionsTests.cs | 135 +- tests/SqlLocalDb.Tests/NotInParallelTests.cs | 63 +- .../NotWindowsFactAttribute.cs | 23 +- tests/SqlLocalDb.Tests/RetryFactDiscoverer.cs | 41 +- tests/SqlLocalDb.Tests/RetryTestCase.cs | 99 +- .../RunAsAdminFactAttribute.cs | 87 +- tests/SqlLocalDb.Tests/SqlLocalDbApiTests.cs | 617 +++-- .../SqlLocalDbExceptionTests.cs | 219 +- .../SqlLocalDbInstanceInfoTests.cs | 255 +- .../SqlLocalDbInstanceManagerTests.cs | 413 ++- .../SqlLocalDbOptionsTests.cs | 47 +- ...LocalDbServiceCollectionExtensionsTests.cs | 213 +- .../SqlLocalDbVersionInfoTests.cs | 143 +- .../WindowsCIOnlyFactAttribute.cs | 29 +- .../WindowsOnlyFactAttribute.cs | 37 +- 67 files changed, 7622 insertions(+), 7732 deletions(-) diff --git a/CommonAssemblyInfo.cs b/CommonAssemblyInfo.cs index f584d28a..de32f1aa 100644 --- a/CommonAssemblyInfo.cs +++ b/CommonAssemblyInfo.cs @@ -1,7 +1,6 @@ -// Copyright (c) Martin Costello, 2012-2018. All rights reserved. +// Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -using System; using System.Reflection; using System.Runtime.InteropServices; diff --git a/samples/TodoApp.Tests/TodoRepositoryTests.cs b/samples/TodoApp.Tests/TodoRepositoryTests.cs index 9e3812fb..e993672e 100644 --- a/samples/TodoApp.Tests/TodoRepositoryTests.cs +++ b/samples/TodoApp.Tests/TodoRepositoryTests.cs @@ -1,114 +1,108 @@ // Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -using System; -using System.Collections.Generic; -using System.Threading.Tasks; using MartinCostello.SqlLocalDb; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using NodaTime; using NodaTime.Testing; using TodoApp.Data; -using Xunit; -using Xunit.Abstractions; -namespace TodoApp.Tests +namespace TodoApp.Tests; + +public class TodoRepositoryTests { - public class TodoRepositoryTests + public TodoRepositoryTests(ITestOutputHelper outputHelper) { - public TodoRepositoryTests(ITestOutputHelper outputHelper) - { - LoggerFactory = outputHelper.ToLoggerFactory(); - } + LoggerFactory = outputHelper.ToLoggerFactory(); + } - private ILoggerFactory LoggerFactory { get; } + private ILoggerFactory LoggerFactory { get; } - [SkippableFact] - public async Task Can_Create_Update_And_Delete_Todo_Items() - { - // Arrange - Skip.IfNot( - OperatingSystem.IsWindows(), - "This test can only be run on Windows."); + [SkippableFact] + public async Task Can_Create_Update_And_Delete_Todo_Items() + { + // Arrange + Skip.IfNot( + OperatingSystem.IsWindows(), + "This test can only be run on Windows."); - var now = new DateTimeOffset(2018, 08, 12, 10, 41, 0, TimeSpan.Zero); - var clock = new FakeClock(Instant.FromDateTimeOffset(now)); + var now = new DateTimeOffset(2018, 08, 12, 10, 41, 0, TimeSpan.Zero); + var clock = new FakeClock(Instant.FromDateTimeOffset(now)); - var options = new SqlLocalDbOptions() - { - AutomaticallyDeleteInstanceFiles = true, - StopOptions = StopInstanceOptions.NoWait, - StopTimeout = TimeSpan.FromSeconds(1), - }; + var options = new SqlLocalDbOptions() + { + AutomaticallyDeleteInstanceFiles = true, + StopOptions = StopInstanceOptions.NoWait, + StopTimeout = TimeSpan.FromSeconds(1), + }; - using var localDB = new SqlLocalDbApi(options, LoggerFactory); - using TemporarySqlLocalDbInstance instance = localDB.CreateTemporaryInstance(deleteFiles: true); + using var localDB = new SqlLocalDbApi(options, LoggerFactory); + using TemporarySqlLocalDbInstance instance = localDB.CreateTemporaryInstance(deleteFiles: true); - var builder = new DbContextOptionsBuilder() - .UseSqlServer(instance.ConnectionString); + var builder = new DbContextOptionsBuilder() + .UseSqlServer(instance.ConnectionString); - using var context = new TodoContext(builder.Options); - await context.Database.MigrateAsync(); + using var context = new TodoContext(builder.Options); + await context.Database.MigrateAsync(); - var target = new TodoRepository(clock, context); + var target = new TodoRepository(clock, context); - // Act - Verify the repository is empty - IList items = await target.GetItemsAsync(); + // Act - Verify the repository is empty + IList items = await target.GetItemsAsync(); - // Assert - Assert.NotNull(items); - Assert.Empty(items); + // Assert + Assert.NotNull(items); + Assert.Empty(items); - // Arrange - Add a new item - string text = "Buy cheese"; + // Arrange - Add a new item + string text = "Buy cheese"; - // Act - TodoItem item = await target.AddItemAsync(text); + // Act + TodoItem item = await target.AddItemAsync(text); - // Assert - Assert.NotNull(item); - Assert.NotEqual(Guid.Empty, item.Id); - Assert.Equal(text, item.Text); - Assert.Equal(now, item.CreatedAt); - Assert.Null(item.CompletedAt); + // Assert + Assert.NotNull(item); + Assert.NotEqual(Guid.Empty, item.Id); + Assert.Equal(text, item.Text); + Assert.Equal(now, item.CreatedAt); + Assert.Null(item.CompletedAt); - // Arrange - Mark the item as completed - Guid id = item.Id; + // Arrange - Mark the item as completed + Guid id = item.Id; - // Act - bool? completeResult = await target.CompleteItemAsync(id); + // Act + bool? completeResult = await target.CompleteItemAsync(id); - // Assert - Assert.True(completeResult); + // Assert + Assert.True(completeResult); - // Act - Verify the repository has one item that is completed - items = await target.GetItemsAsync(); + // Act - Verify the repository has one item that is completed + items = await target.GetItemsAsync(); - // Assert - Assert.NotNull(items); - Assert.NotEmpty(items); - Assert.Equal(1, items.Count); + // Assert + Assert.NotNull(items); + Assert.NotEmpty(items); + Assert.Equal(1, items.Count); - item = items[0]; - Assert.NotNull(item); - Assert.NotEqual(Guid.Empty, item.Id); - Assert.Equal(text, item.Text); - Assert.Equal(now, item.CreatedAt); - Assert.Equal(now, item.CompletedAt); + item = items[0]; + Assert.NotNull(item); + Assert.NotEqual(Guid.Empty, item.Id); + Assert.Equal(text, item.Text); + Assert.Equal(now, item.CreatedAt); + Assert.Equal(now, item.CompletedAt); - // Act - Delete the item - bool deleteResult = await target.DeleteItemAsync(id); + // Act - Delete the item + bool deleteResult = await target.DeleteItemAsync(id); - // Assert - Assert.True(deleteResult); + // Assert + Assert.True(deleteResult); - // Act - Verify the repository is empty again - items = await target.GetItemsAsync(); + // Act - Verify the repository is empty again + items = await target.GetItemsAsync(); - // Assert - Assert.NotNull(items); - Assert.Empty(items); - } + // Assert + Assert.NotNull(items); + Assert.Empty(items); } } diff --git a/samples/TodoApp/Controllers/HomeController.cs b/samples/TodoApp/Controllers/HomeController.cs index 4586629a..ff95ce3d 100644 --- a/samples/TodoApp/Controllers/HomeController.cs +++ b/samples/TodoApp/Controllers/HomeController.cs @@ -2,90 +2,87 @@ // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. using System.Diagnostics; -using System.Threading; -using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using TodoApp.Models; using TodoApp.Services; -namespace TodoApp.Controllers +namespace TodoApp.Controllers; + +public class HomeController : Controller { - public class HomeController : Controller + private readonly ITodoService _service; + + public HomeController(ITodoService service) { - private readonly ITodoService _service; + _service = service; + } - public HomeController(ITodoService service) - { - _service = service; - } + [HttpGet] + public async Task Index(CancellationToken cancellationToken = default) + { + TodoListViewModel model = await _service.GetListAsync(cancellationToken); + return View(model); + } - [HttpGet] - public async Task Index(CancellationToken cancellationToken = default) + [HttpPost] + [ValidateAntiForgeryToken] + public async Task AddItem(string text, CancellationToken cancellationToken = default) + { + if (string.IsNullOrWhiteSpace(text)) { - TodoListViewModel model = await _service.GetListAsync(cancellationToken); - return View(model); + return BadRequest(); } - [HttpPost] - [ValidateAntiForgeryToken] - public async Task AddItem(string text, CancellationToken cancellationToken = default) - { - if (string.IsNullOrWhiteSpace(text)) - { - return BadRequest(); - } - - await _service.AddItemAsync(text, cancellationToken); + await _service.AddItemAsync(text, cancellationToken); - return RedirectToAction(nameof(Index)); - } + return RedirectToAction(nameof(Index)); + } - [HttpPost] - [ValidateAntiForgeryToken] - public async Task CompleteItem(string id, CancellationToken cancellationToken = default) + [HttpPost] + [ValidateAntiForgeryToken] + public async Task CompleteItem(string id, CancellationToken cancellationToken = default) + { + if (string.IsNullOrWhiteSpace(id)) { - if (string.IsNullOrWhiteSpace(id)) - { - return BadRequest(); - } - - bool? result = await _service.CompleteItemAsync(id, cancellationToken); - - if (result == null) - { - return NotFound(); - } + return BadRequest(); + } - if (!result.Value) - { - return BadRequest(); - } + bool? result = await _service.CompleteItemAsync(id, cancellationToken); - return RedirectToAction(nameof(Index)); + if (result == null) + { + return NotFound(); } - [HttpPost] - [ValidateAntiForgeryToken] - public async Task DeleteItem(string id, CancellationToken cancellationToken = default) + if (!result.Value) { - if (string.IsNullOrWhiteSpace(id)) - { - return BadRequest(); - } + return BadRequest(); + } - if (!await _service.DeleteItemAsync(id, cancellationToken)) - { - return NotFound(); - } + return RedirectToAction(nameof(Index)); + } - return RedirectToAction(nameof(Index)); + [HttpPost] + [ValidateAntiForgeryToken] + public async Task DeleteItem(string id, CancellationToken cancellationToken = default) + { + if (string.IsNullOrWhiteSpace(id)) + { + return BadRequest(); } - [HttpGet] - [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] - public IActionResult Error() + if (!await _service.DeleteItemAsync(id, cancellationToken)) { - return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier }); + return NotFound(); } + + return RedirectToAction(nameof(Index)); + } + + [HttpGet] + [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] + public IActionResult Error() + { + return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier }); } } diff --git a/samples/TodoApp/Data/ITodoRepository.cs b/samples/TodoApp/Data/ITodoRepository.cs index 4544645f..9e8d9707 100644 --- a/samples/TodoApp/Data/ITodoRepository.cs +++ b/samples/TodoApp/Data/ITodoRepository.cs @@ -1,62 +1,56 @@ // Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; +namespace TodoApp.Data; -namespace TodoApp.Data +/// +/// Defines the repository for TODO items. +/// +public interface ITodoRepository { /// - /// Defines the repository for TODO items. + /// Adds a new item as an asynchronous operation. /// - public interface ITodoRepository - { - /// - /// Adds a new item as an asynchronous operation. - /// - /// The text of the item to add. - /// The optional cancellation token to use. - /// - /// A representing the asynchronous operation - /// to add the new item that returns the created item. - /// - Task AddItemAsync(string text, CancellationToken cancellationToken = default); + /// The text of the item to add. + /// The optional cancellation token to use. + /// + /// A representing the asynchronous operation + /// to add the new item that returns the created item. + /// + Task AddItemAsync(string text, CancellationToken cancellationToken = default); - /// - /// Marks an item as completed as an asynchronous operation. - /// - /// The id of the item to mark as completed. - /// The optional cancellation token to use. - /// - /// A representing the asynchronous operation - /// to complete the item that if it was completed, - /// if it was already completed, or - /// if an item with the specified Id cannot be found. - /// - Task CompleteItemAsync(Guid id, CancellationToken cancellationToken = default); + /// + /// Marks an item as completed as an asynchronous operation. + /// + /// The id of the item to mark as completed. + /// The optional cancellation token to use. + /// + /// A representing the asynchronous operation + /// to complete the item that if it was completed, + /// if it was already completed, or + /// if an item with the specified Id cannot be found. + /// + Task CompleteItemAsync(Guid id, CancellationToken cancellationToken = default); - /// - /// Deletes an item as an asynchronous operation. - /// - /// The id of the item to delete. - /// The optional cancellation token to use. - /// - /// A representing the asynchronous operation - /// to delete the item that returns if it was deleted, - /// otherwise if an item with the specified Id cannot be found. - /// - Task DeleteItemAsync(Guid id, CancellationToken cancellationToken = default); + /// + /// Deletes an item as an asynchronous operation. + /// + /// The id of the item to delete. + /// The optional cancellation token to use. + /// + /// A representing the asynchronous operation + /// to delete the item that returns if it was deleted, + /// otherwise if an item with the specified Id cannot be found. + /// + Task DeleteItemAsync(Guid id, CancellationToken cancellationToken = default); - /// - /// Returns all items as an asynchronous operation. - /// - /// The optional cancellation token to use. - /// - /// A representing the asynchronous - /// operation to return all of the available items. - /// - Task> GetItemsAsync(CancellationToken cancellationToken = default); - } + /// + /// Returns all items as an asynchronous operation. + /// + /// The optional cancellation token to use. + /// + /// A representing the asynchronous + /// operation to return all of the available items. + /// + Task> GetItemsAsync(CancellationToken cancellationToken = default); } diff --git a/samples/TodoApp/Data/TodoContext.cs b/samples/TodoApp/Data/TodoContext.cs index 81dbcd35..f55790e2 100644 --- a/samples/TodoApp/Data/TodoContext.cs +++ b/samples/TodoApp/Data/TodoContext.cs @@ -3,25 +3,24 @@ using Microsoft.EntityFrameworkCore; -namespace TodoApp.Data +namespace TodoApp.Data; + +/// +/// A class representing the database context for TodoApp. +/// +public class TodoContext : DbContext { /// - /// A class representing the database context for TodoApp. + /// Initializes a new instance of the class. /// - public class TodoContext : DbContext + /// The options for this context. + public TodoContext(DbContextOptions options) + : base(options) { - /// - /// Initializes a new instance of the class. - /// - /// The options for this context. - public TodoContext(DbContextOptions options) - : base(options) - { - } - - /// - /// Gets or sets the database set containing the Todo items. - /// - public DbSet? Items { get; set; } } + + /// + /// Gets or sets the database set containing the Todo items. + /// + public DbSet? Items { get; set; } } diff --git a/samples/TodoApp/Data/TodoInitializer.cs b/samples/TodoApp/Data/TodoInitializer.cs index 18a738b3..728787cf 100644 --- a/samples/TodoApp/Data/TodoInitializer.cs +++ b/samples/TodoApp/Data/TodoInitializer.cs @@ -1,27 +1,24 @@ // Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -using System; using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.DependencyInjection; -namespace TodoApp.Data +namespace TodoApp.Data; + +/// +/// A class representing the initializer for the TodoApp database context. +/// +public static class TodoInitializer { /// - /// A class representing the initializer for the TodoApp database context. + /// Initializes the database for TodoApp. /// - public static class TodoInitializer + /// The to use. + public static void Initialize(IServiceProvider serviceProvider) { - /// - /// Initializes the database for TodoApp. - /// - /// The to use. - public static void Initialize(IServiceProvider serviceProvider) - { - using IServiceScope scope = serviceProvider.CreateScope(); + using IServiceScope scope = serviceProvider.CreateScope(); - var context = scope!.ServiceProvider!.GetService(); - context!.Database.Migrate(); - } + var context = scope!.ServiceProvider!.GetService(); + context!.Database.Migrate(); } } diff --git a/samples/TodoApp/Data/TodoItem.cs b/samples/TodoApp/Data/TodoItem.cs index 0ca8725e..b38f782b 100644 --- a/samples/TodoApp/Data/TodoItem.cs +++ b/samples/TodoApp/Data/TodoItem.cs @@ -1,33 +1,30 @@ // Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -using System; +namespace TodoApp.Data; -namespace TodoApp.Data +/// +/// A class representing the database entity for a TODO item. +/// +public class TodoItem { /// - /// A class representing the database entity for a TODO item. + /// Gets or sets the Id of the item. /// - public class TodoItem - { - /// - /// Gets or sets the Id of the item. - /// - public Guid Id { get; set; } + public Guid Id { get; set; } - /// - /// Gets or sets the text of the item. - /// - public string? Text { get; set; } + /// + /// Gets or sets the text of the item. + /// + public string? Text { get; set; } - /// - /// Gets or sets the date and time the item was created. - /// - public DateTimeOffset CreatedAt { get; set; } + /// + /// Gets or sets the date and time the item was created. + /// + public DateTimeOffset CreatedAt { get; set; } - /// - /// Gets or sets the date and time the item was completed. - /// - public DateTimeOffset? CompletedAt { get; set; } - } + /// + /// Gets or sets the date and time the item was completed. + /// + public DateTimeOffset? CompletedAt { get; set; } } diff --git a/samples/TodoApp/Data/TodoMigration.cs b/samples/TodoApp/Data/TodoMigration.cs index 4c8ff837..53a211ca 100644 --- a/samples/TodoApp/Data/TodoMigration.cs +++ b/samples/TodoApp/Data/TodoMigration.cs @@ -1,62 +1,60 @@ // Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Migrations; -namespace TodoApp.Data +namespace TodoApp.Data; + +/// +/// A class representing a migration that creates the initial database schema. This class cannot be inherited. +/// +[DbContext(typeof(TodoContext))] +[Migration(nameof(TodoMigration))] +public sealed class TodoMigration : Migration { - /// - /// A class representing a migration that creates the initial database schema. This class cannot be inherited. - /// - [DbContext(typeof(TodoContext))] - [Migration(nameof(TodoMigration))] - public sealed class TodoMigration : Migration + /// + protected override void Up(MigrationBuilder migrationBuilder) { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: nameof(TodoContext.Items), - columns: (table) => new - { - Id = table.Column(nullable: false), - Text = table.Column(nullable: false), - CreatedAt = table.Column(nullable: false), - CompletedAt = table.Column(nullable: true), - }, - constraints: (table) => - { - table.PrimaryKey($"PK_{nameof(TodoContext.Items)}", (p) => p.Id); - }); - } + migrationBuilder.CreateTable( + name: nameof(TodoContext.Items), + columns: (table) => new + { + Id = table.Column(nullable: false), + Text = table.Column(nullable: false), + CreatedAt = table.Column(nullable: false), + CompletedAt = table.Column(nullable: true), + }, + constraints: (table) => + { + table.PrimaryKey($"PK_{nameof(TodoContext.Items)}", (p) => p.Id); + }); + } - /// - protected override void Down(MigrationBuilder migrationBuilder) - => migrationBuilder.DropTable(name: nameof(TodoContext.Items)); + /// + protected override void Down(MigrationBuilder migrationBuilder) + => migrationBuilder.DropTable(name: nameof(TodoContext.Items)); - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { - modelBuilder - .HasAnnotation("ProductVersion", "2.1.1-rtm-30846") - .HasAnnotation("Relational:MaxIdentifierLength", 128) - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { + modelBuilder + .HasAnnotation("ProductVersion", "2.1.1-rtm-30846") + .HasAnnotation("Relational:MaxIdentifierLength", 128) + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - modelBuilder.Entity( - typeof(TodoItem).Name, - b => - { - b.Property(nameof(TodoItem.Id)).ValueGeneratedOnAdd(); - b.Property(nameof(TodoItem.Text)); - b.Property(nameof(TodoItem.CreatedAt)); - b.Property(nameof(TodoItem.CompletedAt)); - b.HasKey(nameof(TodoItem.Id)); - b.ToTable(nameof(TodoContext.Items)); - }); - } + modelBuilder.Entity( + typeof(TodoItem).Name, + b => + { + b.Property(nameof(TodoItem.Id)).ValueGeneratedOnAdd(); + b.Property(nameof(TodoItem.Text)); + b.Property(nameof(TodoItem.CreatedAt)); + b.Property(nameof(TodoItem.CompletedAt)); + b.HasKey(nameof(TodoItem.Id)); + b.ToTable(nameof(TodoContext.Items)); + }); } } diff --git a/samples/TodoApp/Data/TodoRepository.cs b/samples/TodoApp/Data/TodoRepository.cs index 7a6f9a0b..be3c996c 100644 --- a/samples/TodoApp/Data/TodoRepository.cs +++ b/samples/TodoApp/Data/TodoRepository.cs @@ -1,107 +1,101 @@ // Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; using NodaTime; -namespace TodoApp.Data +namespace TodoApp.Data; + +/// +/// A class representing a repository of TODO items. This class cannot be inherited. +/// +public sealed class TodoRepository : ITodoRepository { + private readonly IClock _clock; + private readonly TodoContext _context; + /// - /// A class representing a repository of TODO items. This class cannot be inherited. + /// Initializes a new instance of the class. /// - public sealed class TodoRepository : ITodoRepository + /// The to use. + /// The to use. + public TodoRepository(IClock clock, TodoContext context) { - private readonly IClock _clock; - private readonly TodoContext _context; - - /// - /// Initializes a new instance of the class. - /// - /// The to use. - /// The to use. - public TodoRepository(IClock clock, TodoContext context) - { - _clock = clock; - _context = context; - } + _clock = clock; + _context = context; + } - /// - public async Task AddItemAsync(string text, CancellationToken cancellationToken = default) + /// + public async Task AddItemAsync(string text, CancellationToken cancellationToken = default) + { + var item = new TodoItem() { - var item = new TodoItem() - { - CreatedAt = Now(), - Text = text, - }; + CreatedAt = Now(), + Text = text, + }; - _context.Add(item); + _context.Add(item); - await _context.SaveChangesAsync(cancellationToken); + await _context.SaveChangesAsync(cancellationToken); - return item; - } + return item; + } + + /// + public async Task CompleteItemAsync(Guid id, CancellationToken cancellationToken = default) + { + TodoItem? item = await _context.Items!.FindAsync(new object[] { id }, cancellationToken); - /// - public async Task CompleteItemAsync(Guid id, CancellationToken cancellationToken = default) + if (item is null) { - TodoItem? item = await _context.Items!.FindAsync(new object[] { id }, cancellationToken); + return null; + } - if (item is null) - { - return null; - } + if (item.CompletedAt.HasValue) + { + return false; + } - if (item.CompletedAt.HasValue) - { - return false; - } + item.CompletedAt = Now(); - item.CompletedAt = Now(); + _context.Items.Update(item); - _context.Items.Update(item); + await _context.SaveChangesAsync(cancellationToken); - await _context.SaveChangesAsync(cancellationToken); + return true; + } - return true; - } + /// + public async Task DeleteItemAsync(Guid id, CancellationToken cancellationToken = default) + { + TodoItem? item = await _context.Items!.FindAsync(new object[] { id }, cancellationToken); - /// - public async Task DeleteItemAsync(Guid id, CancellationToken cancellationToken = default) + if (item is null) { - TodoItem? item = await _context.Items!.FindAsync(new object[] { id }, cancellationToken); - - if (item is null) - { - return false; - } - - _context.Items.Remove(item); + return false; + } - await _context.SaveChangesAsync(cancellationToken); + _context.Items.Remove(item); - return true; - } + await _context.SaveChangesAsync(cancellationToken); - /// - public async Task> GetItemsAsync(CancellationToken cancellationToken = default) - { - return await _context.Items! - .OrderBy((p) => p.CompletedAt.HasValue) - .ThenBy((p) => p.CreatedAt) - .ToListAsync(cancellationToken); - } + return true; + } - /// - /// Returns the current date and time. - /// - /// - /// The for the current date and time. - /// - private DateTimeOffset Now() => _clock.GetCurrentInstant().ToDateTimeOffset(); + /// + public async Task> GetItemsAsync(CancellationToken cancellationToken = default) + { + return await _context.Items! + .OrderBy((p) => p.CompletedAt.HasValue) + .ThenBy((p) => p.CreatedAt) + .ToListAsync(cancellationToken); } + + /// + /// Returns the current date and time. + /// + /// + /// The for the current date and time. + /// + private DateTimeOffset Now() => _clock.GetCurrentInstant().ToDateTimeOffset(); } diff --git a/samples/TodoApp/Models/ErrorViewModel.cs b/samples/TodoApp/Models/ErrorViewModel.cs index f63ace60..3979f463 100644 --- a/samples/TodoApp/Models/ErrorViewModel.cs +++ b/samples/TodoApp/Models/ErrorViewModel.cs @@ -1,12 +1,11 @@ // Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -namespace TodoApp.Models +namespace TodoApp.Models; + +public class ErrorViewModel { - public class ErrorViewModel - { - public string? RequestId { get; set; } + public string? RequestId { get; set; } - public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); - } + public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); } diff --git a/samples/TodoApp/Models/TodoItemModel.cs b/samples/TodoApp/Models/TodoItemModel.cs index dfb6eead..6b24502c 100644 --- a/samples/TodoApp/Models/TodoItemModel.cs +++ b/samples/TodoApp/Models/TodoItemModel.cs @@ -1,16 +1,15 @@ // Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -namespace TodoApp.Models +namespace TodoApp.Models; + +public class TodoItemModel { - public class TodoItemModel - { - public string? Id { get; set; } + public string? Id { get; set; } - public string? Text { get; set; } + public string? Text { get; set; } - public bool IsCompleted { get; set; } + public bool IsCompleted { get; set; } - public string? LastUpdated { get; set; } - } + public string? LastUpdated { get; set; } } diff --git a/samples/TodoApp/Models/TodoListViewModel.cs b/samples/TodoApp/Models/TodoListViewModel.cs index 51a2bed3..7067c678 100644 --- a/samples/TodoApp/Models/TodoListViewModel.cs +++ b/samples/TodoApp/Models/TodoListViewModel.cs @@ -1,12 +1,9 @@ // Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -using System.Collections.Generic; +namespace TodoApp.Models; -namespace TodoApp.Models +public class TodoListViewModel { - public class TodoListViewModel - { - public ICollection Items { get; set; } = new List(); - } + public ICollection Items { get; set; } = new List(); } diff --git a/samples/TodoApp/Program.cs b/samples/TodoApp/Program.cs index 02eb7983..06758e1c 100644 --- a/samples/TodoApp/Program.cs +++ b/samples/TodoApp/Program.cs @@ -1,21 +1,17 @@ // Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Hosting; +namespace TodoApp; -namespace TodoApp +public static class Program { - public static class Program + public static void Main(string[] args) { - public static void Main(string[] args) - { - CreateWebHostBuilder(args).Build().Run(); - } - - public static IHostBuilder CreateWebHostBuilder(string[] args) => - Host.CreateDefaultBuilder(args) - .ConfigureWebHostDefaults( - (webHostBuilder) => webHostBuilder.UseStartup()); + CreateWebHostBuilder(args).Build().Run(); } + + public static IHostBuilder CreateWebHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .ConfigureWebHostDefaults( + (webHostBuilder) => webHostBuilder.UseStartup()); } diff --git a/samples/TodoApp/Services/ITodoService.cs b/samples/TodoApp/Services/ITodoService.cs index c3556d0b..cea9b853 100644 --- a/samples/TodoApp/Services/ITodoService.cs +++ b/samples/TodoApp/Services/ITodoService.cs @@ -1,60 +1,57 @@ // Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -using System.Threading; -using System.Threading.Tasks; using TodoApp.Models; -namespace TodoApp.Services +namespace TodoApp.Services; + +/// +/// Defines a service for managing TODO items. +/// +public interface ITodoService { /// - /// Defines a service for managing TODO items. + /// Adds a new item as an asynchronous operation. /// - public interface ITodoService - { - /// - /// Adds a new item as an asynchronous operation. - /// - /// The text of the item to add. - /// The cancellation token to use. - /// - /// A representing the asynchronous operation to add the new item. - /// - Task AddItemAsync(string text, CancellationToken cancellationToken); + /// The text of the item to add. + /// The cancellation token to use. + /// + /// A representing the asynchronous operation to add the new item. + /// + Task AddItemAsync(string text, CancellationToken cancellationToken); - /// - /// Marks an item as completed as an asynchronous operation. - /// - /// The id of the item to mark as completed. - /// The cancellation token to use. - /// - /// A representing the asynchronous operation - /// to complete the item that if it was completed, - /// if it was already completed, or - /// if an item with the specified Id cannot be found. - /// - Task CompleteItemAsync(string id, CancellationToken cancellationToken); + /// + /// Marks an item as completed as an asynchronous operation. + /// + /// The id of the item to mark as completed. + /// The cancellation token to use. + /// + /// A representing the asynchronous operation + /// to complete the item that if it was completed, + /// if it was already completed, or + /// if an item with the specified Id cannot be found. + /// + Task CompleteItemAsync(string id, CancellationToken cancellationToken); - /// - /// Deletes an item as an asynchronous operation. - /// - /// The id of the item to delete. - /// The cancellation token to use. - /// - /// A representing the asynchronous operation - /// to delete the item that returns if it was deleted, - /// otherwise if an item with the specified Id cannot be found. - /// - Task DeleteItemAsync(string id, CancellationToken cancellationToken); + /// + /// Deletes an item as an asynchronous operation. + /// + /// The id of the item to delete. + /// The cancellation token to use. + /// + /// A representing the asynchronous operation + /// to delete the item that returns if it was deleted, + /// otherwise if an item with the specified Id cannot be found. + /// + Task DeleteItemAsync(string id, CancellationToken cancellationToken); - /// - /// Returns all the TODO items as an asynchronous operation. - /// - /// The cancellation token to use. - /// - /// A representing the asynchronous - /// operation to return all of the available TODO items. - /// - Task GetListAsync(CancellationToken cancellationToken); - } + /// + /// Returns all the TODO items as an asynchronous operation. + /// + /// The cancellation token to use. + /// + /// A representing the asynchronous + /// operation to return all of the available TODO items. + /// + Task GetListAsync(CancellationToken cancellationToken); } diff --git a/samples/TodoApp/Services/TodoService.cs b/samples/TodoApp/Services/TodoService.cs index 31893073..428f1b62 100644 --- a/samples/TodoApp/Services/TodoService.cs +++ b/samples/TodoApp/Services/TodoService.cs @@ -1,74 +1,69 @@ // Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; using Humanizer; using TodoApp.Data; using TodoApp.Models; -namespace TodoApp.Services +namespace TodoApp.Services; + +/// +/// A class representing the class for managing TODO items. This class cannot be inherited. +/// +public sealed class TodoService : ITodoService { + private readonly ITodoRepository _repository; + /// - /// A class representing the class for managing TODO items. This class cannot be inherited. + /// Initializes a new instance of the class. /// - public sealed class TodoService : ITodoService + /// The to use. + public TodoService(ITodoRepository repository) { - private readonly ITodoRepository _repository; - - /// - /// Initializes a new instance of the class. - /// - /// The to use. - public TodoService(ITodoRepository repository) - { - _repository = repository; - } - - /// - public Task AddItemAsync(string text, CancellationToken cancellationToken) - { - return _repository.AddItemAsync(text, cancellationToken); - } + _repository = repository; + } - /// - public Task CompleteItemAsync(string id, CancellationToken cancellationToken) - { - return _repository.CompleteItemAsync(new Guid(id), cancellationToken); - } + /// + public Task AddItemAsync(string text, CancellationToken cancellationToken) + { + return _repository.AddItemAsync(text, cancellationToken); + } - /// - public Task DeleteItemAsync(string id, CancellationToken cancellationToken) - { - return _repository.DeleteItemAsync(new Guid(id), cancellationToken); - } + /// + public Task CompleteItemAsync(string id, CancellationToken cancellationToken) + { + return _repository.CompleteItemAsync(new Guid(id), cancellationToken); + } - /// - public async Task GetListAsync(CancellationToken cancellationToken) - { - IList items = await _repository.GetItemsAsync(cancellationToken); + /// + public Task DeleteItemAsync(string id, CancellationToken cancellationToken) + { + return _repository.DeleteItemAsync(new Guid(id), cancellationToken); + } - var result = new TodoListViewModel(); + /// + public async Task GetListAsync(CancellationToken cancellationToken) + { + IList items = await _repository.GetItemsAsync(cancellationToken); - foreach (var todo in items) - { - result.Items.Add(MapItem(todo)); - } + var result = new TodoListViewModel(); - return result; + foreach (var todo in items) + { + result.Items.Add(MapItem(todo)); } - private static TodoItemModel MapItem(TodoItem item) + return result; + } + + private static TodoItemModel MapItem(TodoItem item) + { + return new TodoItemModel() { - return new TodoItemModel() - { - Id = item.Id.ToString(), - IsCompleted = item.CompletedAt.HasValue, - LastUpdated = (item.CompletedAt ?? item.CreatedAt).Humanize(), - Text = item.Text, - }; - } + Id = item.Id.ToString(), + IsCompleted = item.CompletedAt.HasValue, + LastUpdated = (item.CompletedAt ?? item.CreatedAt).Humanize(), + Text = item.Text, + }; } } diff --git a/samples/TodoApp/Startup.cs b/samples/TodoApp/Startup.cs index 6642bbdf..2ba1b655 100644 --- a/samples/TodoApp/Startup.cs +++ b/samples/TodoApp/Startup.cs @@ -1,87 +1,79 @@ // Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -using System; using MartinCostello.SqlLocalDb; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; using NodaTime; using TodoApp.Data; using TodoApp.Services; -namespace TodoApp +namespace TodoApp; + +public class Startup { - public class Startup + public Startup(IConfiguration configuration) { - public Startup(IConfiguration configuration) - { - Configuration = configuration; - } + Configuration = configuration; + } - public IConfiguration Configuration { get; } + public IConfiguration Configuration { get; } - public void ConfigureServices(IServiceCollection services) - { - services.AddSqlLocalDB(); + public void ConfigureServices(IServiceCollection services) + { + services.AddSqlLocalDB(); + + services.AddSingleton((_) => SystemClock.Instance); + services.AddScoped(); + services.AddScoped(); - services.AddSingleton((_) => SystemClock.Instance); - services.AddScoped(); - services.AddScoped(); + services.AddControllersWithViews(); - services.AddControllersWithViews(); + services.AddDbContext(AddTodoContext); + } - services.AddDbContext(AddTodoContext); + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); } + else + { + app.UseExceptionHandler("/Home/Error"); + app.UseHsts(); + } + + app.UseHttpsRedirection(); + app.UseStaticFiles(); + app.UseRouting(); + app.UseEndpoints((endpoints) => endpoints.MapDefaultControllerRoute()); + + // Ensure that the database and schema exists + TodoInitializer.Initialize(app.ApplicationServices); + } - public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + private static void AddTodoContext(IServiceProvider serviceProvider, DbContextOptionsBuilder options) + { + // Check that SQL Server LocalDB is installed + ISqlLocalDbApi localDB = serviceProvider.GetRequiredService(); + + if (!localDB.IsLocalDBInstalled()) { - if (env.IsDevelopment()) - { - app.UseDeveloperExceptionPage(); - } - else - { - app.UseExceptionHandler("/Home/Error"); - app.UseHsts(); - } - - app.UseHttpsRedirection(); - app.UseStaticFiles(); - app.UseRouting(); - app.UseEndpoints((endpoints) => endpoints.MapDefaultControllerRoute()); - - // Ensure that the database and schema exists - TodoInitializer.Initialize(app.ApplicationServices); + throw new NotSupportedException("SQL LocalDB is not installed."); } - private static void AddTodoContext(IServiceProvider serviceProvider, DbContextOptionsBuilder options) + // Get the configured SQL LocalDB instance to store the TODO items in, creating it if it does not exist + IConfiguration config = serviceProvider.GetRequiredService(); + ISqlLocalDbInstanceInfo instance = localDB.GetOrCreateInstance(config["SqlLocalDbInstance"]); + + // Ensure that the SQL LocalDB instance is running and start it if not already running + if (!instance.IsRunning) { - // Check that SQL Server LocalDB is installed - ISqlLocalDbApi localDB = serviceProvider.GetRequiredService(); - - if (!localDB.IsLocalDBInstalled()) - { - throw new NotSupportedException("SQL LocalDB is not installed."); - } - - // Get the configured SQL LocalDB instance to store the TODO items in, creating it if it does not exist - IConfiguration config = serviceProvider.GetRequiredService(); - ISqlLocalDbInstanceInfo instance = localDB.GetOrCreateInstance(config["SqlLocalDbInstance"]); - - // Ensure that the SQL LocalDB instance is running and start it if not already running - if (!instance.IsRunning) - { - instance.Manage().Start(); - } - - // Get the SQL connection string to use to connect to the LocalDB instance - string connectionString = instance.GetConnectionString(); - options.UseSqlServer(connectionString); + instance.Manage().Start(); } + + // Get the SQL connection string to use to connect to the LocalDB instance + string connectionString = instance.GetConnectionString(); + options.UseSqlServer(connectionString); } } diff --git a/src/SqlLocalDb/EventIds.cs b/src/SqlLocalDb/EventIds.cs index aec8c238..59c80500 100644 --- a/src/SqlLocalDb/EventIds.cs +++ b/src/SqlLocalDb/EventIds.cs @@ -3,303 +3,302 @@ using Microsoft.Extensions.Logging; -namespace MartinCostello.SqlLocalDb +namespace MartinCostello.SqlLocalDb; + +/// +/// A class containing trace event Ids. This class cannot be inherited. +/// +internal static class EventIds { + //// Add new events to the end of the class to preserve the Ids. + + /// + /// The for when the SQL LocalDB Instance API is loaded. This field is read-only. + /// + internal static readonly EventId NativeApiLoaded = new EventId(++Id, nameof(NativeApiLoaded)); + + /// + /// The for when the SQL LocalDB Instance API fails to load. This field is read-only. + /// + internal static readonly EventId NativeApiLoadFailed = new EventId(++Id, nameof(NativeApiLoadFailed)); + + /// + /// The for when the SQL LocalDB Instance API is not loaded. This field is read-only. + /// + internal static readonly EventId NativeApiNotLoaded = new EventId(++Id, nameof(NativeApiNotLoaded)); + + /// + /// The for when the SQL LocalDB Instance API version is overridden. This field is read-only. + /// + internal static readonly EventId NativeApiVersionOverriddenByUser = new EventId(++Id, nameof(NativeApiVersionOverriddenByUser)); + + /// + /// The for when the SQL LocalDB Instance API version specified as an override cannot be found. This field is read-only. + /// + internal static readonly EventId NativeApiVersionOverrideNotFound = new EventId(++Id, nameof(NativeApiVersionOverrideNotFound)); + + /// + /// The for when the SQL LocalDB Instance API cannot be found. This field is read-only. + /// + internal static readonly EventId NoNativeApiFound = new EventId(++Id, nameof(NoNativeApiFound)); + + /// + /// The for when the SQL LocalDB Instance API path configured in the registry cannot be found. This field is read-only. + /// + internal static readonly EventId NativeApiPathNotFound = new EventId(++Id, nameof(NativeApiPathNotFound)); + + /// + /// The for when a native function export from the SQL LocalDB Instance API cannot be found. This field is read-only. + /// + internal static readonly EventId NativeFunctionNotFound = new EventId(++Id, nameof(NativeFunctionNotFound)); + + /// + /// The for when the SQL LocalDB Instance API is not installed. This field is read-only. + /// + internal static readonly EventId NotInstalled = new EventId(++Id, nameof(NotInstalled)); + + /// + /// The for when a SQL LocalDB instance is being created. This field is read-only. + /// + internal static readonly EventId CreatingInstance = new EventId(++Id, nameof(CreatingInstance)); + + /// + /// The for when creating a SQL LocalDB instance fails. This field is read-only. + /// + internal static readonly EventId CreatingInstanceFailed = new EventId(++Id, nameof(CreatingInstanceFailed)); + + /// + /// The for when a SQL LocalDB instance has been created. This field is read-only. + /// + internal static readonly EventId CreatedInstance = new EventId(++Id, nameof(CreatedInstance)); + + /// + /// The for when a SQL LocalDB instance is being deleted. This field is read-only. + /// + internal static readonly EventId DeletingInstance = new EventId(++Id, nameof(DeletingInstance)); + + /// + /// The for when deleting a SQL LocalDB instance fails. This field is read-only. + /// + internal static readonly EventId DeletingInstanceFailed = new EventId(++Id, nameof(DeletingInstanceFailed)); + + /// + /// The for when deleting a SQL LocalDB instance fails because it cannot be found. This field is read-only. + /// + internal static readonly EventId DeletingInstanceFailedAsCannotBeNotFound = new EventId(++Id, nameof(DeletingInstanceFailedAsCannotBeNotFound)); + + /// + /// The for when deleting a SQL LocalDB instance fails because it is in use. This field is read-only. + /// + internal static readonly EventId DeletingInstanceFailedAsInUse = new EventId(++Id, nameof(DeletingInstanceFailedAsInUse)); + + /// + /// The for when a SQL LocalDB instance has been deleted. This field is read-only. + /// + internal static readonly EventId DeletedInstance = new EventId(++Id, nameof(DeletedInstance)); + + /// + /// The for when the files for a SQL LocalDB instance are being deleted. This field is read-only. + /// + internal static readonly EventId DeletingInstanceFiles = new EventId(++Id, nameof(DeletingInstanceFiles)); + + /// + /// The for when the files for a SQL LocalDB instance fail to be deleted. This field is read-only. + /// + internal static readonly EventId DeletingInstanceFilesFailed = new EventId(++Id, nameof(DeletingInstanceFilesFailed)); + + /// + /// The for when the files for a SQL LocalDB instance have been deleted. This field is read-only. + /// + internal static readonly EventId DeletedInstanceFiles = new EventId(++Id, nameof(DeletedInstanceFiles)); + + /// + /// The for when getting information about a SQL LocalDB instance. This field is read-only. + /// + internal static readonly EventId GettingInstanceInfo = new EventId(++Id, nameof(GettingInstanceInfo)); + + /// + /// The for when getting information about a SQL LocalDB instance fails. This field is read-only. + /// + internal static readonly EventId GettingInstanceInfoFailed = new EventId(++Id, nameof(GettingInstanceInfoFailed)); + + /// + /// The for when information about a SQL LocalDB instance was retrieved. This field is read-only. + /// + internal static readonly EventId GotInstanceInfo = new EventId(++Id, nameof(GotInstanceInfo)); + + /// + /// The for when getting SQL LocalDB instance names. This field is read-only. + /// + internal static readonly EventId GettingInstanceNames = new EventId(++Id, nameof(GettingInstanceNames)); + + /// + /// The for when getting SQL LocalDB instance names fails. This field is read-only. + /// + internal static readonly EventId GettingInstanceNamesFailed = new EventId(++Id, nameof(GettingInstanceNamesFailed)); + + /// + /// The for when SQL LocalDB instance names are retrieved. This field is read-only. + /// + internal static readonly EventId GotInstanceNames = new EventId(++Id, nameof(GotInstanceNames)); + + /// + /// The for when getting information about a SQL LocalDB version. This field is read-only. + /// + internal static readonly EventId GettingVersionInfo = new EventId(++Id, nameof(GettingVersionInfo)); + + /// + /// The for when getting information about a SQL LocalDB version fails. This field is read-only. + /// + internal static readonly EventId GettingVersionInfoFailed = new EventId(++Id, nameof(GettingVersionInfoFailed)); + + /// + /// The for when information about a SQL LocalDB version was retrieved. This field is read-only. + /// + internal static readonly EventId GotVersionInfo = new EventId(++Id, nameof(GotVersionInfo)); + + /// + /// The for when getting SQL LocalDB versions. This field is read-only. + /// + internal static readonly EventId GettingVersions = new EventId(++Id, nameof(GettingVersions)); + + /// + /// The for when getting SQL LocalDB versions fails. This field is read-only. + /// + internal static readonly EventId GettingVersionsFailed = new EventId(++Id, nameof(GettingVersionsFailed)); + + /// + /// The for when SQL LocalDB instance versions are retrieved. This field is read-only. + /// + internal static readonly EventId GotVersions = new EventId(++Id, nameof(GotVersions)); + + /// + /// The for when a specified Language Id is invalid. This field is read-only. + /// + internal static readonly EventId InvalidLanguageId = new EventId(++Id, nameof(InvalidLanguageId)); + + /// + /// The for when a specified registry key name is invalid. This field is read-only. + /// + internal static readonly EventId InvalidRegistryKey = new EventId(++Id, nameof(InvalidRegistryKey)); + + /// + /// The for when a registry key cannot be found. This field is read-only. + /// + internal static readonly EventId RegistryKeyNotFound = new EventId(++Id, nameof(RegistryKeyNotFound)); + + /// + /// The for when a SQL LocalDB instance is starting. This field is read-only. + /// + internal static readonly EventId StartingInstance = new EventId(++Id, nameof(StartingInstance)); + + /// + /// The for when a SQL LocalDB instance fails to start. This field is read-only. + /// + internal static readonly EventId StartingInstanceFailed = new EventId(++Id, nameof(StartingInstanceFailed)); + + /// + /// The for when a SQL LocalDB instance has started. This field is read-only. + /// + internal static readonly EventId StartedInstance = new EventId(++Id, nameof(StartedInstance)); + + /// + /// The for when a SQL LocalDB instance is stopping. This field is read-only. + /// + internal static readonly EventId StoppingInstance = new EventId(++Id, nameof(StoppingInstance)); + + /// + /// The for when a SQL LocalDB instance fails to stop. This field is read-only. + /// + internal static readonly EventId StoppingInstanceFailed = new EventId(++Id, nameof(StoppingInstanceFailed)); + + /// + /// The for when a SQL LocalDB instance has stopped. This field is read-only. + /// + internal static readonly EventId StoppedInstance = new EventId(++Id, nameof(StoppedInstance)); + + /// + /// The for when SQL LocalDB API tracing is starting. This field is read-only. + /// + internal static readonly EventId StartingTracing = new EventId(++Id, nameof(StartingTracing)); + + /// + /// The for when tracing for SQL LocalDB API fails to start. This field is read-only. + /// + internal static readonly EventId StartingTracingFailed = new EventId(++Id, nameof(StartingTracingFailed)); + /// - /// A class containing trace event Ids. This class cannot be inherited. - /// - internal static class EventIds - { - //// Add new events to the end of the class to preserve the Ids. - - /// - /// The for when the SQL LocalDB Instance API is loaded. This field is read-only. - /// - internal static readonly EventId NativeApiLoaded = new EventId(++Id, nameof(NativeApiLoaded)); - - /// - /// The for when the SQL LocalDB Instance API fails to load. This field is read-only. - /// - internal static readonly EventId NativeApiLoadFailed = new EventId(++Id, nameof(NativeApiLoadFailed)); - - /// - /// The for when the SQL LocalDB Instance API is not loaded. This field is read-only. - /// - internal static readonly EventId NativeApiNotLoaded = new EventId(++Id, nameof(NativeApiNotLoaded)); - - /// - /// The for when the SQL LocalDB Instance API version is overridden. This field is read-only. - /// - internal static readonly EventId NativeApiVersionOverriddenByUser = new EventId(++Id, nameof(NativeApiVersionOverriddenByUser)); - - /// - /// The for when the SQL LocalDB Instance API version specified as an override cannot be found. This field is read-only. - /// - internal static readonly EventId NativeApiVersionOverrideNotFound = new EventId(++Id, nameof(NativeApiVersionOverrideNotFound)); - - /// - /// The for when the SQL LocalDB Instance API cannot be found. This field is read-only. - /// - internal static readonly EventId NoNativeApiFound = new EventId(++Id, nameof(NoNativeApiFound)); - - /// - /// The for when the SQL LocalDB Instance API path configured in the registry cannot be found. This field is read-only. - /// - internal static readonly EventId NativeApiPathNotFound = new EventId(++Id, nameof(NativeApiPathNotFound)); - - /// - /// The for when a native function export from the SQL LocalDB Instance API cannot be found. This field is read-only. - /// - internal static readonly EventId NativeFunctionNotFound = new EventId(++Id, nameof(NativeFunctionNotFound)); - - /// - /// The for when the SQL LocalDB Instance API is not installed. This field is read-only. - /// - internal static readonly EventId NotInstalled = new EventId(++Id, nameof(NotInstalled)); - - /// - /// The for when a SQL LocalDB instance is being created. This field is read-only. - /// - internal static readonly EventId CreatingInstance = new EventId(++Id, nameof(CreatingInstance)); - - /// - /// The for when creating a SQL LocalDB instance fails. This field is read-only. - /// - internal static readonly EventId CreatingInstanceFailed = new EventId(++Id, nameof(CreatingInstanceFailed)); - - /// - /// The for when a SQL LocalDB instance has been created. This field is read-only. - /// - internal static readonly EventId CreatedInstance = new EventId(++Id, nameof(CreatedInstance)); - - /// - /// The for when a SQL LocalDB instance is being deleted. This field is read-only. - /// - internal static readonly EventId DeletingInstance = new EventId(++Id, nameof(DeletingInstance)); - - /// - /// The for when deleting a SQL LocalDB instance fails. This field is read-only. - /// - internal static readonly EventId DeletingInstanceFailed = new EventId(++Id, nameof(DeletingInstanceFailed)); - - /// - /// The for when deleting a SQL LocalDB instance fails because it cannot be found. This field is read-only. - /// - internal static readonly EventId DeletingInstanceFailedAsCannotBeNotFound = new EventId(++Id, nameof(DeletingInstanceFailedAsCannotBeNotFound)); - - /// - /// The for when deleting a SQL LocalDB instance fails because it is in use. This field is read-only. - /// - internal static readonly EventId DeletingInstanceFailedAsInUse = new EventId(++Id, nameof(DeletingInstanceFailedAsInUse)); - - /// - /// The for when a SQL LocalDB instance has been deleted. This field is read-only. - /// - internal static readonly EventId DeletedInstance = new EventId(++Id, nameof(DeletedInstance)); - - /// - /// The for when the files for a SQL LocalDB instance are being deleted. This field is read-only. - /// - internal static readonly EventId DeletingInstanceFiles = new EventId(++Id, nameof(DeletingInstanceFiles)); - - /// - /// The for when the files for a SQL LocalDB instance fail to be deleted. This field is read-only. - /// - internal static readonly EventId DeletingInstanceFilesFailed = new EventId(++Id, nameof(DeletingInstanceFilesFailed)); - - /// - /// The for when the files for a SQL LocalDB instance have been deleted. This field is read-only. - /// - internal static readonly EventId DeletedInstanceFiles = new EventId(++Id, nameof(DeletedInstanceFiles)); - - /// - /// The for when getting information about a SQL LocalDB instance. This field is read-only. - /// - internal static readonly EventId GettingInstanceInfo = new EventId(++Id, nameof(GettingInstanceInfo)); - - /// - /// The for when getting information about a SQL LocalDB instance fails. This field is read-only. - /// - internal static readonly EventId GettingInstanceInfoFailed = new EventId(++Id, nameof(GettingInstanceInfoFailed)); - - /// - /// The for when information about a SQL LocalDB instance was retrieved. This field is read-only. - /// - internal static readonly EventId GotInstanceInfo = new EventId(++Id, nameof(GotInstanceInfo)); - - /// - /// The for when getting SQL LocalDB instance names. This field is read-only. - /// - internal static readonly EventId GettingInstanceNames = new EventId(++Id, nameof(GettingInstanceNames)); - - /// - /// The for when getting SQL LocalDB instance names fails. This field is read-only. - /// - internal static readonly EventId GettingInstanceNamesFailed = new EventId(++Id, nameof(GettingInstanceNamesFailed)); - - /// - /// The for when SQL LocalDB instance names are retrieved. This field is read-only. - /// - internal static readonly EventId GotInstanceNames = new EventId(++Id, nameof(GotInstanceNames)); - - /// - /// The for when getting information about a SQL LocalDB version. This field is read-only. - /// - internal static readonly EventId GettingVersionInfo = new EventId(++Id, nameof(GettingVersionInfo)); - - /// - /// The for when getting information about a SQL LocalDB version fails. This field is read-only. - /// - internal static readonly EventId GettingVersionInfoFailed = new EventId(++Id, nameof(GettingVersionInfoFailed)); - - /// - /// The for when information about a SQL LocalDB version was retrieved. This field is read-only. - /// - internal static readonly EventId GotVersionInfo = new EventId(++Id, nameof(GotVersionInfo)); - - /// - /// The for when getting SQL LocalDB versions. This field is read-only. - /// - internal static readonly EventId GettingVersions = new EventId(++Id, nameof(GettingVersions)); - - /// - /// The for when getting SQL LocalDB versions fails. This field is read-only. - /// - internal static readonly EventId GettingVersionsFailed = new EventId(++Id, nameof(GettingVersionsFailed)); - - /// - /// The for when SQL LocalDB instance versions are retrieved. This field is read-only. - /// - internal static readonly EventId GotVersions = new EventId(++Id, nameof(GotVersions)); - - /// - /// The for when a specified Language Id is invalid. This field is read-only. - /// - internal static readonly EventId InvalidLanguageId = new EventId(++Id, nameof(InvalidLanguageId)); - - /// - /// The for when a specified registry key name is invalid. This field is read-only. - /// - internal static readonly EventId InvalidRegistryKey = new EventId(++Id, nameof(InvalidRegistryKey)); - - /// - /// The for when a registry key cannot be found. This field is read-only. - /// - internal static readonly EventId RegistryKeyNotFound = new EventId(++Id, nameof(RegistryKeyNotFound)); - - /// - /// The for when a SQL LocalDB instance is starting. This field is read-only. - /// - internal static readonly EventId StartingInstance = new EventId(++Id, nameof(StartingInstance)); - - /// - /// The for when a SQL LocalDB instance fails to start. This field is read-only. - /// - internal static readonly EventId StartingInstanceFailed = new EventId(++Id, nameof(StartingInstanceFailed)); - - /// - /// The for when a SQL LocalDB instance has started. This field is read-only. - /// - internal static readonly EventId StartedInstance = new EventId(++Id, nameof(StartedInstance)); - - /// - /// The for when a SQL LocalDB instance is stopping. This field is read-only. - /// - internal static readonly EventId StoppingInstance = new EventId(++Id, nameof(StoppingInstance)); - - /// - /// The for when a SQL LocalDB instance fails to stop. This field is read-only. - /// - internal static readonly EventId StoppingInstanceFailed = new EventId(++Id, nameof(StoppingInstanceFailed)); - - /// - /// The for when a SQL LocalDB instance has stopped. This field is read-only. - /// - internal static readonly EventId StoppedInstance = new EventId(++Id, nameof(StoppedInstance)); - - /// - /// The for when SQL LocalDB API tracing is starting. This field is read-only. - /// - internal static readonly EventId StartingTracing = new EventId(++Id, nameof(StartingTracing)); - - /// - /// The for when tracing for SQL LocalDB API fails to start. This field is read-only. - /// - internal static readonly EventId StartingTracingFailed = new EventId(++Id, nameof(StartingTracingFailed)); - - /// - /// The for when SQL LocalDB API tracing is started. This field is read-only. - /// - internal static readonly EventId StartedTracing = new EventId(++Id, nameof(StartedTracing)); - - /// - /// The for when SQL LocalDB API tracing is stopping. This field is read-only. - /// - internal static readonly EventId StoppedTracing = new EventId(++Id, nameof(StoppedTracing)); - - /// - /// The for when tracing for SQL LocalDB API fails to stop. This field is read-only. - /// - internal static readonly EventId StoppingTracingFailed = new EventId(++Id, nameof(StoppingTracingFailed)); - - /// - /// The for when SQL LocalDB API tracing is stopped. This field is read-only. - /// - internal static readonly EventId StoppingTracing = new EventId(++Id, nameof(StoppingTracing)); - - /// - /// The for when a temporary SQL LocalDB API instance fails to stop. This field is read-only. - /// - internal static readonly EventId StopTemporaryInstanceFailed = new EventId(++Id, nameof(StopTemporaryInstanceFailed)); - - /// - /// The for when a SQL LocalDB instance is being shared. This field is read-only. - /// - internal static readonly EventId SharingInstance = new EventId(++Id, nameof(SharingInstance)); - - /// - /// The for when sharing a SQL LocalDB instance fails. This field is read-only. - /// - internal static readonly EventId SharingInstanceFailed = new EventId(++Id, nameof(SharingInstanceFailed)); - - /// - /// The for when a SQL LocalDB instance has been shared. This field is read-only. - /// - internal static readonly EventId SharedInstance = new EventId(++Id, nameof(SharedInstance)); - - /// - /// The for when a SQL LocalDB instance is being unshared. This field is read-only. - /// - internal static readonly EventId UnsharingInstance = new EventId(++Id, nameof(UnsharingInstance)); - - /// - /// The for when unsharing a SQL LocalDB instance fails. This field is read-only. - /// - internal static readonly EventId UnsharingInstanceFailed = new EventId(++Id, nameof(UnsharingInstanceFailed)); - - /// - /// The for when a SQL LocalDB instance has been unshared. This field is read-only. - /// - internal static readonly EventId UnsharedInstance = new EventId(++Id, nameof(UnsharedInstance)); - - /// - /// The for when the SQL LocalDB Instance API is unloaded. This field is read-only. - /// - internal static readonly EventId NativeApiUnloaded = new EventId(++Id, nameof(NativeApiUnloaded)); - - /// - /// The for when the SQL LocalDB Instance API returns a generic error. This field is read-only. - /// - internal static readonly EventId GenericError = new EventId(++Id, nameof(GenericError)); - - /// - /// The base Id for the event Ids. - /// - private const int BaseId = 0; - - /// - /// Gets or sets the current Id for assigning event Ids. - /// - private static int Id { get; set; } = BaseId; - } + /// The for when SQL LocalDB API tracing is started. This field is read-only. + /// + internal static readonly EventId StartedTracing = new EventId(++Id, nameof(StartedTracing)); + + /// + /// The for when SQL LocalDB API tracing is stopping. This field is read-only. + /// + internal static readonly EventId StoppedTracing = new EventId(++Id, nameof(StoppedTracing)); + + /// + /// The for when tracing for SQL LocalDB API fails to stop. This field is read-only. + /// + internal static readonly EventId StoppingTracingFailed = new EventId(++Id, nameof(StoppingTracingFailed)); + + /// + /// The for when SQL LocalDB API tracing is stopped. This field is read-only. + /// + internal static readonly EventId StoppingTracing = new EventId(++Id, nameof(StoppingTracing)); + + /// + /// The for when a temporary SQL LocalDB API instance fails to stop. This field is read-only. + /// + internal static readonly EventId StopTemporaryInstanceFailed = new EventId(++Id, nameof(StopTemporaryInstanceFailed)); + + /// + /// The for when a SQL LocalDB instance is being shared. This field is read-only. + /// + internal static readonly EventId SharingInstance = new EventId(++Id, nameof(SharingInstance)); + + /// + /// The for when sharing a SQL LocalDB instance fails. This field is read-only. + /// + internal static readonly EventId SharingInstanceFailed = new EventId(++Id, nameof(SharingInstanceFailed)); + + /// + /// The for when a SQL LocalDB instance has been shared. This field is read-only. + /// + internal static readonly EventId SharedInstance = new EventId(++Id, nameof(SharedInstance)); + + /// + /// The for when a SQL LocalDB instance is being unshared. This field is read-only. + /// + internal static readonly EventId UnsharingInstance = new EventId(++Id, nameof(UnsharingInstance)); + + /// + /// The for when unsharing a SQL LocalDB instance fails. This field is read-only. + /// + internal static readonly EventId UnsharingInstanceFailed = new EventId(++Id, nameof(UnsharingInstanceFailed)); + + /// + /// The for when a SQL LocalDB instance has been unshared. This field is read-only. + /// + internal static readonly EventId UnsharedInstance = new EventId(++Id, nameof(UnsharedInstance)); + + /// + /// The for when the SQL LocalDB Instance API is unloaded. This field is read-only. + /// + internal static readonly EventId NativeApiUnloaded = new EventId(++Id, nameof(NativeApiUnloaded)); + + /// + /// The for when the SQL LocalDB Instance API returns a generic error. This field is read-only. + /// + internal static readonly EventId GenericError = new EventId(++Id, nameof(GenericError)); + + /// + /// The base Id for the event Ids. + /// + private const int BaseId = 0; + + /// + /// Gets or sets the current Id for assigning event Ids. + /// + private static int Id { get; set; } = BaseId; } diff --git a/src/SqlLocalDb/ILoggerExtensions.cs b/src/SqlLocalDb/ILoggerExtensions.cs index 83555da4..d304795a 100644 --- a/src/SqlLocalDb/ILoggerExtensions.cs +++ b/src/SqlLocalDb/ILoggerExtensions.cs @@ -5,723 +5,722 @@ using System.Globalization; using Microsoft.Extensions.Logging; -namespace MartinCostello.SqlLocalDb +namespace MartinCostello.SqlLocalDb; + +/// +/// A class containing extension methods for the interface. This class cannot be inherited. +/// +internal static class ILoggerExtensions { /// - /// A class containing extension methods for the interface. This class cannot be inherited. - /// - internal static class ILoggerExtensions - { - /// - /// Logging delegate for when a SQL LocalDB instance has been created. - /// - private static readonly Action _createdInstance = LoggerMessage.Define( - LogLevel.Debug, - EventIds.CreatedInstance, - SR.ILoggerExtensions_CreatedInstanceFormat); - - /// - /// Logging delegate for when a SQL LocalDB instance is being created. - /// - private static readonly Action _creatingInstance = LoggerMessage.Define( - LogLevel.Debug, - EventIds.CreatingInstance, - SR.ILoggerExtensions_CreatingInstanceFormat); - - /// - /// Logging delegate for when a SQL LocalDB instance has been deleted. - /// - private static readonly Action _deletedInstance = LoggerMessage.Define( - LogLevel.Debug, - EventIds.DeletedInstance, - SR.ILoggerExtensions_DeletedInstanceFormat); - - /// - /// Logging delegate for when a SQL LocalDB instance is being deleting. - /// - private static readonly Action _deletingInstance = LoggerMessage.Define( - LogLevel.Debug, - EventIds.DeletingInstance, - SR.ILoggerExtensions_DeletingFormat); - - /// - /// Logging delegate for when a SQL LocalDB instance that could not be deleted. - /// - private static readonly Action _deletingInstanceFailed = LoggerMessage.Define( - LogLevel.Error, - EventIds.DeletingInstanceFailed, - SR.ILoggerExtensions_DeleteFailedFormat); - - /// - /// Logging delegate for when a SQL LocalDB instance that could not be deleted as it is still in use. - /// - private static readonly Action _deletingInstanceFailedAsInUse = LoggerMessage.Define( - LogLevel.Warning, - EventIds.DeletingInstanceFailedAsInUse, - SR.ILoggerExtensions_DeleteFailedAsInUseFormat); - - /// - /// Logging delegate for when a SQL LocalDB instance that could not be deleted because it could not be found. - /// - private static readonly Action _deletingInstanceFailedAsInstanceNotFound = LoggerMessage.Define( - LogLevel.Debug, - EventIds.DeletingInstanceFailedAsCannotBeNotFound, - SR.ILoggerExtensions_InstanceDoesNotExistFormat); - - /// - /// Logging delegate for when a SQL LocalDB instance files have been deleted. - /// - private static readonly Action _deletedInstanceFiles = LoggerMessage.Define( - LogLevel.Debug, - EventIds.DeletedInstanceFiles, - SR.ILoggerExtensions_DeletedInstanceFilesFormat); - - /// - /// Logging delegate for when a SQL LocalDB instance files are being deleted. - /// - private static readonly Action _deletingInstanceFiles = LoggerMessage.Define( - LogLevel.Debug, - EventIds.DeletingInstanceFiles, - SR.ILoggerExtensions_DeletingInstanceFilesFormat); - - /// - /// Logging delegate for when a SQL LocalDB instance files could not be deleted. - /// - private static readonly Action _deletingInstanceFilesFailed = LoggerMessage.Define( - LogLevel.Error, - EventIds.DeletingInstanceFilesFailed, - SR.ILoggerExtensions_DeletingInstanceFilesFailedFormat); - - /// - /// Logging delegate for when getting information about a SQL LocalDB instance. - /// - private static readonly Action _gettingInstanceInfo = LoggerMessage.Define( - LogLevel.Debug, - EventIds.GettingInstanceInfo, - SR.ILoggerExtensions_GettingInfoFormat); - - /// - /// Logging delegate for when information about a SQL LocalDB instance was got. - /// - private static readonly Action _gotInstanceInfo = LoggerMessage.Define( - LogLevel.Debug, - EventIds.GotInstanceInfo, - SR.ILoggerExtensions_GotInfoFormat); - - /// - /// Logging delegate for when getting SQL LocalDB instance names. - /// - private static readonly Action _gettingInstanceNames = LoggerMessage.Define( - LogLevel.Debug, - EventIds.GettingInstanceNames, - SR.ILoggerExtensions_GetInstances); - - /// - /// Logging delegate for when SQL LocalDB instance names were got. - /// - private static readonly Action _gotInstanceNames = LoggerMessage.Define( - LogLevel.Debug, - EventIds.GotInstanceNames, - SR.ILoggerExtensions_GotInstancesFormat); - - /// - /// Logging delegate for when getting information about a SQL LocalDB version. - /// - private static readonly Action _gettingVersionInfo = LoggerMessage.Define( - LogLevel.Debug, - EventIds.GettingVersionInfo, - SR.ILoggerExtensions_GetVersionInfoFormat); - - /// - /// Logging delegate for when information about a SQL LocalDB version was got. - /// - private static readonly Action _gotVersionInfo = LoggerMessage.Define( - LogLevel.Debug, - EventIds.GotVersionInfo, - SR.ILoggerExtensions_GotVersionInfoFormat); - - /// - /// Logging delegate for when getting SQL LocalDB versions. - /// - private static readonly Action _gettingVersions = LoggerMessage.Define( - LogLevel.Debug, - EventIds.GettingVersions, - SR.ILoggerExtensions_GetVersions); - - /// - /// Logging delegate for when SQL LocalDB versions were got. - /// - private static readonly Action _gotVersions = LoggerMessage.Define( - LogLevel.Debug, - EventIds.GotVersions, - SR.ILoggerExtensions_GotVersionsFormat); - - /// - /// Logging delegate for when a invalid Language Id is used. - /// - private static readonly Action _invalidLanguageId = LoggerMessage.Define( - LogLevel.Warning, - EventIds.InvalidLanguageId, - SR.ILoggerExtensions_InvalidLanguageIdFormat); - - /// - /// Logging delegate for when a invalid SQL LocalDB Instance API registry key was found. - /// - private static readonly Action _invalidRegistryKey = LoggerMessage.Define( - LogLevel.Warning, - EventIds.InvalidRegistryKey, - SR.ILoggerExtensions_InvalidRegistryKeyNameFormat); - - /// - /// Logging delegate for when a SQL LocalDB Instance API function could not be found. - /// - private static readonly Action _nativeApiFunctionNotFound = LoggerMessage.Define( - LogLevel.Error, - EventIds.NativeFunctionNotFound, - SR.ILoggerExtensions_FunctionNotFoundFormat); - - /// - /// Logging delegate for when the SQL LocalDB Instance API DLL was loaded. - /// - private static readonly Action _nativeApiLoaded = LoggerMessage.Define( - LogLevel.Debug, - EventIds.NativeApiLoaded, - SR.ILoggerExtensions_NativeApiLoadedFormat); - - /// - /// Logging delegate for when the SQL LocalDB Instance API DLL could not loaded. - /// - private static readonly Action _nativeApiLoadFailed = LoggerMessage.Define( - LogLevel.Error, - EventIds.NativeApiLoadFailed, - SR.ILoggerExtensions_NativeApiLoadFailedFormat); - - /// - /// Logging delegate for when the SQL LocalDB Instance API could not be found. - /// - private static readonly Action _nativeApiNotFound = LoggerMessage.Define( - LogLevel.Warning, - EventIds.NoNativeApiFound, - SR.ILoggerExtensions_NoNativeApiFound); - - /// - /// Logging delegate for when the SQL LocalDB Instance API DLL was not loaded. - /// - private static readonly Action _nativeApiNotLoaded = LoggerMessage.Define( - LogLevel.Warning, - EventIds.NativeApiNotLoaded, - SR.ILoggerExtensions_NativeApiNotLoaded); - - /// - /// Logging delegate for when the SQL LocalDB Instance API DLL could not be found at the configured path. - /// - private static readonly Action _nativeApiPathNotFound = LoggerMessage.Define( - LogLevel.Error, - EventIds.NativeApiPathNotFound, - SR.ILoggerExtensions_NativeApiNotFoundFormat); - - /// - /// Logging delegate for when the SQL LocalDB Instance API DLL was unloaded. - /// - private static readonly Action _nativeApiUnloaded = LoggerMessage.Define( - LogLevel.Debug, - EventIds.NativeApiUnloaded, - SR.ILoggerExtensions_NativeApiUnloadedFormat); - - /// - /// Logging delegate for when the version of the SQL LocalDB Instance API to use was overridden by the user. - /// - private static readonly Action _nativeApiVersionOverriddenByUser = LoggerMessage.Define( - LogLevel.Debug, - EventIds.NativeApiVersionOverriddenByUser, - SR.ILoggerExtensions_NativeApiVersionOverriddenByUserFormat); - - /// - /// Logging delegate for when the version of the SQL LocalDB Instance API specified by the user could not be found. - /// - private static readonly Action _nativeApiVersionOverrideNotFound = LoggerMessage.Define( - LogLevel.Warning, - EventIds.NativeApiVersionOverrideNotFound, - SR.ILoggerExtensions_OverrideVersionNotFoundFormat); - - /// - /// Logging delegate for when SQL LocalDB is not installed. - /// - private static readonly Action _notInstalled = LoggerMessage.Define( - LogLevel.Warning, - EventIds.NotInstalled, - SR.ILoggerExtensions_NotInstalled); - - /// - /// Logging delegate for when the SQL LocalDB Instance API registry key cannot be found. - /// - private static readonly Action _registryKeyNotFound = LoggerMessage.Define( - LogLevel.Warning, - EventIds.RegistryKeyNotFound, - SR.ILoggerExtensions_RegistryKeyNotFoundFormat); - - /// - /// Logging delegate for when a SQL LocalDB instance was shared. - /// - private static readonly Action _sharedInstance = LoggerMessage.Define( - LogLevel.Debug, - EventIds.SharedInstance, - SR.ILoggerExtensions_SharedInstanceFormat); - - /// - /// Logging delegate for when a SQL LocalDB instance is shared. - /// - private static readonly Action _sharingInstance = LoggerMessage.Define( - LogLevel.Debug, - EventIds.SharingInstance, - SR.ILoggerExtensions_SharingInstanceFormat); - - /// - /// Logging delegate for when a SQL LocalDB instance is starting. - /// - private static readonly Action _startedInstance = LoggerMessage.Define( - LogLevel.Debug, - EventIds.StartedInstance, - SR.ILoggerExtensions_StartedFormat); - - /// - /// Logging delegate for when a SQL LocalDB instance is starting. - /// - private static readonly Action _startingInstance = LoggerMessage.Define( - LogLevel.Debug, - EventIds.StartingInstance, - SR.ILoggerExtensions_StartingFormat); - - /// - /// Logging delegate for when SQL LocalDB tracing has started. - /// - private static readonly Action _startedTracing = LoggerMessage.Define( - LogLevel.Debug, - EventIds.StartedTracing, - SR.ILoggerExtensions_StartedTracing); - - /// - /// Logging delegate for when SQL LocalDB tracing is starting. - /// - private static readonly Action _startingTracing = LoggerMessage.Define( - LogLevel.Debug, - EventIds.StartingTracing, - SR.ILoggerExtensions_StartTracing); - - /// - /// Logging delegate for when a SQL LocalDB instance was stopped. - /// - private static readonly Action _stoppedInstance = LoggerMessage.Define( - LogLevel.Debug, - EventIds.StoppedInstance, - SR.ILoggerExtensions_StoppedFormat); - - /// - /// Logging delegate for when a SQL LocalDB instance is stopping. - /// - private static readonly Action _stoppingInstance = LoggerMessage.Define( - LogLevel.Debug, - EventIds.StoppingInstance, - SR.ILoggerExtensions_StoppingFormat); - - /// - /// Logging delegate for when a temporary SQL LocalDB instance failed to stop. - /// - private static readonly Action _stoppingTemporaryInstanceFailed = LoggerMessage.Define( - LogLevel.Error, - EventIds.StopTemporaryInstanceFailed, - SR.ILoggerExtensions_StopFailedFormat); - - /// - /// Logging delegate for when SQL LocalDB instance is stopped. - /// - private static readonly Action _stoppedTracing = LoggerMessage.Define( - LogLevel.Debug, - EventIds.StoppedTracing, - SR.ILoggerExtensions_StoppedTracing); - - /// - /// Logging delegate for when SQL LocalDB instance is stopping. - /// - private static readonly Action _stoppingTracing = LoggerMessage.Define( - LogLevel.Debug, - EventIds.StoppingTracing, - SR.ILoggerExtensions_StoppingTracing); - - /// - /// Logging delegate for when a SQL LocalDB instance was unshared. - /// - private static readonly Action _unsharedInstance = LoggerMessage.Define( - LogLevel.Debug, - EventIds.UnsharedInstance, - SR.ILoggerExtensions_StoppedSharingFormat); - - /// - /// Logging delegate for when a SQL LocalDB instance is unshared. - /// - private static readonly Action _unsharingInstance = LoggerMessage.Define( - LogLevel.Debug, - EventIds.UnsharingInstance, - SR.ILoggerExtensions_StoppingSharingFormat); - - /// - /// Logs that a SQL LocalDB instance has been created. - /// - /// The logger to use. - /// The name of the instance that was created. - /// The LocalDB version the instance that was created with. - internal static void CreatedInstance(this ILogger logger, string instanceName, string version) - => _createdInstance(logger, instanceName, version, null); - - /// - /// Logs that a SQL LocalDB instance is being created. - /// - /// The logger to use. - /// The name of the instance that is being created. - /// The LocalDB version to create the instance with. - internal static void CreatingInstance(this ILogger logger, string instanceName, string version) - => _creatingInstance(logger, instanceName, version, null); - - /// - /// Logs that a SQL LocalDB instance has been deleted. - /// - /// The logger to use. - /// The name of the instance that was created. - internal static void DeletedInstance(this ILogger logger, string instanceName) - => _deletedInstance(logger, instanceName, null); - - /// - /// Logs that a SQL LocalDB instance is being deleted. - /// - /// The logger to use. - /// The name of the instance that is being deleted. - internal static void DeletingInstance(this ILogger logger, string instanceName) - => _deletingInstance(logger, instanceName, null); - - /// - /// Logs that a SQL LocalDB instance could not be deleted. - /// - /// The logger to use. - /// The name of the instance that could not be deleted. - /// The error code. - internal static void DeletingInstanceFailed(this ILogger logger, string instanceName, int error) - => _deletingInstanceFailed(logger, instanceName, error.ToString("X", CultureInfo.InvariantCulture), null); - - /// - /// Logs that a SQL LocalDB instance could not be deleted because it is still in use. - /// - /// The logger to use. - /// The exception that was thrown. - /// The name of the instance that could not be deleted. - internal static void DeletingInstanceFailedAsInUse(this ILogger logger, Exception exception, string? instanceName) - => _deletingInstanceFailedAsInUse(logger, instanceName, exception); - - /// - /// Logs that a SQL LocalDB instance could not be deleted because it could not be found. - /// - /// The logger to use. - /// The name of the instance that could not be deleted. - internal static void DeletingInstanceFailedAsNotFound(this ILogger logger, string instanceName) - => _deletingInstanceFailedAsInstanceNotFound(logger, instanceName, null); - - /// - /// Logs that a SQL LocalDB instance's files have been deleted. - /// - /// The logger to use. - /// The name of the instance whose files were deleted. - /// The path of the files that were deleted. - internal static void DeletedInstanceFiles(this ILogger logger, string instanceName, string instancePath) - => _deletedInstanceFiles(logger, instanceName, instancePath, null); - - /// - /// Logs that a SQL LocalDB instance's files are being deleted. - /// - /// The logger to use. - /// The name of the instance whose files are being deleted. - /// The path of the files to be deleted. - internal static void DeletingInstanceFiles(this ILogger logger, string instanceName, string instancePath) - => _deletingInstanceFiles(logger, instanceName, instancePath, null); - - /// - /// Logs that a SQL LocalDB instance's files could not be deleted. - /// - /// The logger to use. - /// The name of the instance whose files could not be deleted. - /// The path of the files that failed to be deleted. - internal static void DeletingInstanceFilesFailed(this ILogger logger, string instanceName, string? instancePath) - => _deletingInstanceFilesFailed(logger, instanceName, instancePath, null); - - /// - /// Logs that information about a SQL LocalDB instance is being retrieved. - /// - /// The logger to use. - /// The name of the instance information is being retrieved for. - internal static void GettingInstanceInfo(this ILogger logger, string instanceName) - => _gettingInstanceInfo(logger, instanceName, null); - - /// - /// Logs that information about a SQL LocalDB instance was retrieved. - /// - /// The logger to use. - /// The name of the instance information was retrieved for. - internal static void GotInstanceInfo(this ILogger logger, string instanceName) - => _gotInstanceInfo(logger, instanceName, null); - - /// - /// Logs that SQL LocalDB instance names are being retrieved. - /// - /// The logger to use. - internal static void GettingInstanceNames(this ILogger logger) - => _gettingInstanceNames(logger, null); - - /// - /// Logs that SQL LocalDB instance names were retrieved. - /// - /// The logger to use. - /// The number of SQL LocalDB instances retrieved. - internal static void GotInstanceNames(this ILogger logger, int count) - => _gotInstanceNames(logger, count, null); - - /// - /// Logs that information about a SQL LocalDB version is being retrieved. - /// - /// The logger to use. - /// The version information is being retrieved for. - internal static void GettingVersionInfo(this ILogger logger, string version) - => _gettingVersionInfo(logger, version, null); - - /// - /// Logs that information about a SQL LocalDB version was retrieved. - /// - /// The logger to use. - /// The version information was retrieved for. - internal static void GotVersionInfo(this ILogger logger, string version) - => _gotVersionInfo(logger, version, null); - - /// - /// Logs that SQL LocalDB versions are being retrieved. - /// - /// The logger to use. - internal static void GettingVersions(this ILogger logger) - => _gettingVersions(logger, null); - - /// - /// Logs that SQL LocalDB versions were retrieved. - /// - /// The logger to use. - /// The number of SQL LocalDB versions retrieved. - internal static void GotVersions(this ILogger logger, int count) - => _gotVersions(logger, count, null); - - /// - /// Logs that an invalid Language Id is configured. - /// - /// The logger to use. - /// The version used. - internal static void InvalidLanguageId(this ILogger logger, int languageId) - => _invalidLanguageId(logger, languageId, null); - - /// - /// Logs that an invalid SQL LocalDB Instance API registry key was found. - /// - /// The logger to use. - /// The version used. - internal static void InvalidRegistryKey(this ILogger logger, string version) - => _invalidRegistryKey(logger, version, null); - - /// - /// Logs that a SQL LocalDB Instance API function could not be found. - /// - /// The logger to use. - /// The name of the function that could not be found. - internal static void NativeApiFunctionNotFound(this ILogger logger, string functionName) - => _nativeApiFunctionNotFound(logger, functionName, null); - - /// - /// Logs that the SQL LocalDB Instance API DLL could not be found at the configured path. - /// - /// The logger to use. - /// The path to the file that could not be found. - internal static void NativeApiLibraryNotFound(this ILogger logger, string path) - => _nativeApiPathNotFound(logger, path, null); - - /// - /// Logs that the SQL LocalDB Instance API DLL was loaded. - /// - /// The logger to use. - /// The full path to the DLL that was loaded. - internal static void NativeApiLoaded(this ILogger logger, string fileName) - => _nativeApiLoaded(logger, fileName, null); - - /// - /// Logs that the SQL LocalDB Instance API DLL could not loaded. - /// - /// The logger to use. - /// The full path to the DLL that could not be loaded. - /// The error code. - internal static void NativeApiLoadFailed(this ILogger logger, string fileName, int error) - => _nativeApiLoadFailed(logger, fileName, error, null); - - /// - /// Logs that the SQL LocalDB Instance API could not be found. - /// - /// The logger to use. - internal static void NativeApiNotFound(this ILogger logger) - => _nativeApiNotFound(logger, null); - - /// - /// Logs that the SQL LocalDB Instance API DLL was not loaded. - /// - /// The logger to use. - internal static void NativeApiNotLoaded(this ILogger logger) - => _nativeApiNotLoaded(logger, null); - - /// - /// Logs that the SQL LocalDB Instance API DLL was unloaded. - /// - /// The logger to use. - /// The full path to the DLL that was unloaded. - internal static void NativeApiUnloaded(this ILogger logger, string fileName) - => _nativeApiUnloaded(logger, fileName, null); - - /// - /// Logs that the version of the SQL LocalDB Instance API to use was overridden by the user. - /// - /// The logger to use. - /// The version used. - internal static void NativeApiVersionOverriddenByUser(this ILogger logger, Version version) - => _nativeApiVersionOverriddenByUser(logger, version, null); - - /// - /// Logs that the version of the SQL LocalDB Instance API specified by the user could not be found. - /// - /// The logger to use. - /// The version specified to be used. - internal static void NativeApiVersionOverrideNotFound(this ILogger logger, string version) - => _nativeApiVersionOverrideNotFound(logger, version, null); - - /// - /// Logs that SQL LocalDB is not installed. - /// - /// The logger to use. - internal static void NotInstalled(this ILogger logger) - => _notInstalled(logger, null); - - /// - /// Logs that the SQL LocalDB Instance API registry key cannot be found. - /// - /// The logger to use. - /// The name of the registry key that was not found. - internal static void RegistryKeyNotFound(this ILogger logger, string keyName) - => _registryKeyNotFound(logger, keyName, null); - - /// - /// Logs that a SQL LocalDB instance is being shared. - /// - /// The logger to use. - /// The name of the instance that is being shared. - /// The SID of the instance owner. - /// The shared name for the LocalDB instance to share as. - internal static void SharingInstance(this ILogger logger, string instanceName, string ownerSid, string sharedInstanceName) - => _sharingInstance(logger, instanceName, ownerSid, sharedInstanceName, null); - - /// - /// Logs that a SQL LocalDB instance was shared. - /// - /// The logger to use. - /// The name of the instance that was shared. - /// The SID of the instance owner. - /// The shared name for the LocalDB instance to share as. - internal static void SharedInstance(this ILogger logger, string instanceName, string ownerSid, string sharedInstanceName) - => _sharedInstance(logger, instanceName, ownerSid, sharedInstanceName, null); - - /// - /// Logs that a SQL LocalDB instance was started. - /// - /// The logger to use. - /// The name of the instance that was started. - /// The named pipe the instance is listening on. - internal static void StartedInstance(this ILogger logger, string instanceName, string namedPipe) - => _startedInstance(logger, instanceName, namedPipe, null); - - /// - /// Logs that a SQL LocalDB instance is starting. - /// - /// The logger to use. - /// The name of the instance that is starting. - internal static void StartingInstance(this ILogger logger, string instanceName) - => _startingInstance(logger, instanceName, null); - - /// - /// Logs that SQL LocalDB tracing was started. - /// - /// The logger to use. - internal static void StartedTracing(this ILogger logger) - => _startedTracing(logger, null); - - /// - /// Logs that SQL LocalDB tracing is starting. - /// - /// The logger to use. - internal static void StartingTracing(this ILogger logger) - => _startingTracing(logger, null); - - /// - /// Logs that a SQL LocalDB instance was stopped. - /// - /// The logger to use. - /// The name of the instance that was stopped. - /// The time taken for the instance to stop. - internal static void StoppedInstance(this ILogger logger, string instanceName, TimeSpan elapsed) - => _stoppedInstance(logger, instanceName, elapsed, null); - - /// - /// Logs that a SQL LocalDB instance is stopping. - /// - /// The logger to use. - /// The name of the instance that is stopping. - /// The timeout used. - /// The stop options used. - internal static void StoppingInstance(this ILogger logger, string instanceName, TimeSpan timeout, StopInstanceOptions options) - => _stoppingInstance(logger, instanceName, timeout, options, null); - - /// - /// Logs that a temporary SQL LocalDB instance failed to stop. - /// - /// The logger to use. - /// The name of the instance that failed to stop. - /// The error code. - internal static void StoppingTemporaryInstanceFailed(this ILogger logger, string instanceName, int error) - => _stoppingTemporaryInstanceFailed(logger, instanceName, error.ToString("X", CultureInfo.InvariantCulture), null); - - /// - /// Logs that SQL LocalDB tracing was stopped. - /// - /// The logger to use. - internal static void StoppedTracing(this ILogger logger) - => _stoppedTracing(logger, null); - - /// - /// Logs that SQL LocalDB tracing is stopping. - /// - /// The logger to use. - internal static void StoppingTracing(this ILogger logger) - => _stoppingTracing(logger, null); - - /// - /// Logs that a SQL LocalDB instance is being unshared. - /// - /// The logger to use. - /// The name of the instance that is being shared. - internal static void UnsharingInstance(this ILogger logger, string instanceName) - => _unsharingInstance(logger, instanceName, null); - - /// - /// Logs that a SQL LocalDB instance was shared. - /// - /// The logger to use. - /// The name of the instance that was shared. - internal static void UnsharedInstance(this ILogger logger, string instanceName) - => _unsharedInstance(logger, instanceName, null); - } + /// Logging delegate for when a SQL LocalDB instance has been created. + /// + private static readonly Action _createdInstance = LoggerMessage.Define( + LogLevel.Debug, + EventIds.CreatedInstance, + SR.ILoggerExtensions_CreatedInstanceFormat); + + /// + /// Logging delegate for when a SQL LocalDB instance is being created. + /// + private static readonly Action _creatingInstance = LoggerMessage.Define( + LogLevel.Debug, + EventIds.CreatingInstance, + SR.ILoggerExtensions_CreatingInstanceFormat); + + /// + /// Logging delegate for when a SQL LocalDB instance has been deleted. + /// + private static readonly Action _deletedInstance = LoggerMessage.Define( + LogLevel.Debug, + EventIds.DeletedInstance, + SR.ILoggerExtensions_DeletedInstanceFormat); + + /// + /// Logging delegate for when a SQL LocalDB instance is being deleting. + /// + private static readonly Action _deletingInstance = LoggerMessage.Define( + LogLevel.Debug, + EventIds.DeletingInstance, + SR.ILoggerExtensions_DeletingFormat); + + /// + /// Logging delegate for when a SQL LocalDB instance that could not be deleted. + /// + private static readonly Action _deletingInstanceFailed = LoggerMessage.Define( + LogLevel.Error, + EventIds.DeletingInstanceFailed, + SR.ILoggerExtensions_DeleteFailedFormat); + + /// + /// Logging delegate for when a SQL LocalDB instance that could not be deleted as it is still in use. + /// + private static readonly Action _deletingInstanceFailedAsInUse = LoggerMessage.Define( + LogLevel.Warning, + EventIds.DeletingInstanceFailedAsInUse, + SR.ILoggerExtensions_DeleteFailedAsInUseFormat); + + /// + /// Logging delegate for when a SQL LocalDB instance that could not be deleted because it could not be found. + /// + private static readonly Action _deletingInstanceFailedAsInstanceNotFound = LoggerMessage.Define( + LogLevel.Debug, + EventIds.DeletingInstanceFailedAsCannotBeNotFound, + SR.ILoggerExtensions_InstanceDoesNotExistFormat); + + /// + /// Logging delegate for when a SQL LocalDB instance files have been deleted. + /// + private static readonly Action _deletedInstanceFiles = LoggerMessage.Define( + LogLevel.Debug, + EventIds.DeletedInstanceFiles, + SR.ILoggerExtensions_DeletedInstanceFilesFormat); + + /// + /// Logging delegate for when a SQL LocalDB instance files are being deleted. + /// + private static readonly Action _deletingInstanceFiles = LoggerMessage.Define( + LogLevel.Debug, + EventIds.DeletingInstanceFiles, + SR.ILoggerExtensions_DeletingInstanceFilesFormat); + + /// + /// Logging delegate for when a SQL LocalDB instance files could not be deleted. + /// + private static readonly Action _deletingInstanceFilesFailed = LoggerMessage.Define( + LogLevel.Error, + EventIds.DeletingInstanceFilesFailed, + SR.ILoggerExtensions_DeletingInstanceFilesFailedFormat); + + /// + /// Logging delegate for when getting information about a SQL LocalDB instance. + /// + private static readonly Action _gettingInstanceInfo = LoggerMessage.Define( + LogLevel.Debug, + EventIds.GettingInstanceInfo, + SR.ILoggerExtensions_GettingInfoFormat); + + /// + /// Logging delegate for when information about a SQL LocalDB instance was got. + /// + private static readonly Action _gotInstanceInfo = LoggerMessage.Define( + LogLevel.Debug, + EventIds.GotInstanceInfo, + SR.ILoggerExtensions_GotInfoFormat); + + /// + /// Logging delegate for when getting SQL LocalDB instance names. + /// + private static readonly Action _gettingInstanceNames = LoggerMessage.Define( + LogLevel.Debug, + EventIds.GettingInstanceNames, + SR.ILoggerExtensions_GetInstances); + + /// + /// Logging delegate for when SQL LocalDB instance names were got. + /// + private static readonly Action _gotInstanceNames = LoggerMessage.Define( + LogLevel.Debug, + EventIds.GotInstanceNames, + SR.ILoggerExtensions_GotInstancesFormat); + + /// + /// Logging delegate for when getting information about a SQL LocalDB version. + /// + private static readonly Action _gettingVersionInfo = LoggerMessage.Define( + LogLevel.Debug, + EventIds.GettingVersionInfo, + SR.ILoggerExtensions_GetVersionInfoFormat); + + /// + /// Logging delegate for when information about a SQL LocalDB version was got. + /// + private static readonly Action _gotVersionInfo = LoggerMessage.Define( + LogLevel.Debug, + EventIds.GotVersionInfo, + SR.ILoggerExtensions_GotVersionInfoFormat); + + /// + /// Logging delegate for when getting SQL LocalDB versions. + /// + private static readonly Action _gettingVersions = LoggerMessage.Define( + LogLevel.Debug, + EventIds.GettingVersions, + SR.ILoggerExtensions_GetVersions); + + /// + /// Logging delegate for when SQL LocalDB versions were got. + /// + private static readonly Action _gotVersions = LoggerMessage.Define( + LogLevel.Debug, + EventIds.GotVersions, + SR.ILoggerExtensions_GotVersionsFormat); + + /// + /// Logging delegate for when a invalid Language Id is used. + /// + private static readonly Action _invalidLanguageId = LoggerMessage.Define( + LogLevel.Warning, + EventIds.InvalidLanguageId, + SR.ILoggerExtensions_InvalidLanguageIdFormat); + + /// + /// Logging delegate for when a invalid SQL LocalDB Instance API registry key was found. + /// + private static readonly Action _invalidRegistryKey = LoggerMessage.Define( + LogLevel.Warning, + EventIds.InvalidRegistryKey, + SR.ILoggerExtensions_InvalidRegistryKeyNameFormat); + + /// + /// Logging delegate for when a SQL LocalDB Instance API function could not be found. + /// + private static readonly Action _nativeApiFunctionNotFound = LoggerMessage.Define( + LogLevel.Error, + EventIds.NativeFunctionNotFound, + SR.ILoggerExtensions_FunctionNotFoundFormat); + + /// + /// Logging delegate for when the SQL LocalDB Instance API DLL was loaded. + /// + private static readonly Action _nativeApiLoaded = LoggerMessage.Define( + LogLevel.Debug, + EventIds.NativeApiLoaded, + SR.ILoggerExtensions_NativeApiLoadedFormat); + + /// + /// Logging delegate for when the SQL LocalDB Instance API DLL could not loaded. + /// + private static readonly Action _nativeApiLoadFailed = LoggerMessage.Define( + LogLevel.Error, + EventIds.NativeApiLoadFailed, + SR.ILoggerExtensions_NativeApiLoadFailedFormat); + + /// + /// Logging delegate for when the SQL LocalDB Instance API could not be found. + /// + private static readonly Action _nativeApiNotFound = LoggerMessage.Define( + LogLevel.Warning, + EventIds.NoNativeApiFound, + SR.ILoggerExtensions_NoNativeApiFound); + + /// + /// Logging delegate for when the SQL LocalDB Instance API DLL was not loaded. + /// + private static readonly Action _nativeApiNotLoaded = LoggerMessage.Define( + LogLevel.Warning, + EventIds.NativeApiNotLoaded, + SR.ILoggerExtensions_NativeApiNotLoaded); + + /// + /// Logging delegate for when the SQL LocalDB Instance API DLL could not be found at the configured path. + /// + private static readonly Action _nativeApiPathNotFound = LoggerMessage.Define( + LogLevel.Error, + EventIds.NativeApiPathNotFound, + SR.ILoggerExtensions_NativeApiNotFoundFormat); + + /// + /// Logging delegate for when the SQL LocalDB Instance API DLL was unloaded. + /// + private static readonly Action _nativeApiUnloaded = LoggerMessage.Define( + LogLevel.Debug, + EventIds.NativeApiUnloaded, + SR.ILoggerExtensions_NativeApiUnloadedFormat); + + /// + /// Logging delegate for when the version of the SQL LocalDB Instance API to use was overridden by the user. + /// + private static readonly Action _nativeApiVersionOverriddenByUser = LoggerMessage.Define( + LogLevel.Debug, + EventIds.NativeApiVersionOverriddenByUser, + SR.ILoggerExtensions_NativeApiVersionOverriddenByUserFormat); + + /// + /// Logging delegate for when the version of the SQL LocalDB Instance API specified by the user could not be found. + /// + private static readonly Action _nativeApiVersionOverrideNotFound = LoggerMessage.Define( + LogLevel.Warning, + EventIds.NativeApiVersionOverrideNotFound, + SR.ILoggerExtensions_OverrideVersionNotFoundFormat); + + /// + /// Logging delegate for when SQL LocalDB is not installed. + /// + private static readonly Action _notInstalled = LoggerMessage.Define( + LogLevel.Warning, + EventIds.NotInstalled, + SR.ILoggerExtensions_NotInstalled); + + /// + /// Logging delegate for when the SQL LocalDB Instance API registry key cannot be found. + /// + private static readonly Action _registryKeyNotFound = LoggerMessage.Define( + LogLevel.Warning, + EventIds.RegistryKeyNotFound, + SR.ILoggerExtensions_RegistryKeyNotFoundFormat); + + /// + /// Logging delegate for when a SQL LocalDB instance was shared. + /// + private static readonly Action _sharedInstance = LoggerMessage.Define( + LogLevel.Debug, + EventIds.SharedInstance, + SR.ILoggerExtensions_SharedInstanceFormat); + + /// + /// Logging delegate for when a SQL LocalDB instance is shared. + /// + private static readonly Action _sharingInstance = LoggerMessage.Define( + LogLevel.Debug, + EventIds.SharingInstance, + SR.ILoggerExtensions_SharingInstanceFormat); + + /// + /// Logging delegate for when a SQL LocalDB instance is starting. + /// + private static readonly Action _startedInstance = LoggerMessage.Define( + LogLevel.Debug, + EventIds.StartedInstance, + SR.ILoggerExtensions_StartedFormat); + + /// + /// Logging delegate for when a SQL LocalDB instance is starting. + /// + private static readonly Action _startingInstance = LoggerMessage.Define( + LogLevel.Debug, + EventIds.StartingInstance, + SR.ILoggerExtensions_StartingFormat); + + /// + /// Logging delegate for when SQL LocalDB tracing has started. + /// + private static readonly Action _startedTracing = LoggerMessage.Define( + LogLevel.Debug, + EventIds.StartedTracing, + SR.ILoggerExtensions_StartedTracing); + + /// + /// Logging delegate for when SQL LocalDB tracing is starting. + /// + private static readonly Action _startingTracing = LoggerMessage.Define( + LogLevel.Debug, + EventIds.StartingTracing, + SR.ILoggerExtensions_StartTracing); + + /// + /// Logging delegate for when a SQL LocalDB instance was stopped. + /// + private static readonly Action _stoppedInstance = LoggerMessage.Define( + LogLevel.Debug, + EventIds.StoppedInstance, + SR.ILoggerExtensions_StoppedFormat); + + /// + /// Logging delegate for when a SQL LocalDB instance is stopping. + /// + private static readonly Action _stoppingInstance = LoggerMessage.Define( + LogLevel.Debug, + EventIds.StoppingInstance, + SR.ILoggerExtensions_StoppingFormat); + + /// + /// Logging delegate for when a temporary SQL LocalDB instance failed to stop. + /// + private static readonly Action _stoppingTemporaryInstanceFailed = LoggerMessage.Define( + LogLevel.Error, + EventIds.StopTemporaryInstanceFailed, + SR.ILoggerExtensions_StopFailedFormat); + + /// + /// Logging delegate for when SQL LocalDB instance is stopped. + /// + private static readonly Action _stoppedTracing = LoggerMessage.Define( + LogLevel.Debug, + EventIds.StoppedTracing, + SR.ILoggerExtensions_StoppedTracing); + + /// + /// Logging delegate for when SQL LocalDB instance is stopping. + /// + private static readonly Action _stoppingTracing = LoggerMessage.Define( + LogLevel.Debug, + EventIds.StoppingTracing, + SR.ILoggerExtensions_StoppingTracing); + + /// + /// Logging delegate for when a SQL LocalDB instance was unshared. + /// + private static readonly Action _unsharedInstance = LoggerMessage.Define( + LogLevel.Debug, + EventIds.UnsharedInstance, + SR.ILoggerExtensions_StoppedSharingFormat); + + /// + /// Logging delegate for when a SQL LocalDB instance is unshared. + /// + private static readonly Action _unsharingInstance = LoggerMessage.Define( + LogLevel.Debug, + EventIds.UnsharingInstance, + SR.ILoggerExtensions_StoppingSharingFormat); + + /// + /// Logs that a SQL LocalDB instance has been created. + /// + /// The logger to use. + /// The name of the instance that was created. + /// The LocalDB version the instance that was created with. + internal static void CreatedInstance(this ILogger logger, string instanceName, string version) + => _createdInstance(logger, instanceName, version, null); + + /// + /// Logs that a SQL LocalDB instance is being created. + /// + /// The logger to use. + /// The name of the instance that is being created. + /// The LocalDB version to create the instance with. + internal static void CreatingInstance(this ILogger logger, string instanceName, string version) + => _creatingInstance(logger, instanceName, version, null); + + /// + /// Logs that a SQL LocalDB instance has been deleted. + /// + /// The logger to use. + /// The name of the instance that was created. + internal static void DeletedInstance(this ILogger logger, string instanceName) + => _deletedInstance(logger, instanceName, null); + + /// + /// Logs that a SQL LocalDB instance is being deleted. + /// + /// The logger to use. + /// The name of the instance that is being deleted. + internal static void DeletingInstance(this ILogger logger, string instanceName) + => _deletingInstance(logger, instanceName, null); + + /// + /// Logs that a SQL LocalDB instance could not be deleted. + /// + /// The logger to use. + /// The name of the instance that could not be deleted. + /// The error code. + internal static void DeletingInstanceFailed(this ILogger logger, string instanceName, int error) + => _deletingInstanceFailed(logger, instanceName, error.ToString("X", CultureInfo.InvariantCulture), null); + + /// + /// Logs that a SQL LocalDB instance could not be deleted because it is still in use. + /// + /// The logger to use. + /// The exception that was thrown. + /// The name of the instance that could not be deleted. + internal static void DeletingInstanceFailedAsInUse(this ILogger logger, Exception exception, string? instanceName) + => _deletingInstanceFailedAsInUse(logger, instanceName, exception); + + /// + /// Logs that a SQL LocalDB instance could not be deleted because it could not be found. + /// + /// The logger to use. + /// The name of the instance that could not be deleted. + internal static void DeletingInstanceFailedAsNotFound(this ILogger logger, string instanceName) + => _deletingInstanceFailedAsInstanceNotFound(logger, instanceName, null); + + /// + /// Logs that a SQL LocalDB instance's files have been deleted. + /// + /// The logger to use. + /// The name of the instance whose files were deleted. + /// The path of the files that were deleted. + internal static void DeletedInstanceFiles(this ILogger logger, string instanceName, string instancePath) + => _deletedInstanceFiles(logger, instanceName, instancePath, null); + + /// + /// Logs that a SQL LocalDB instance's files are being deleted. + /// + /// The logger to use. + /// The name of the instance whose files are being deleted. + /// The path of the files to be deleted. + internal static void DeletingInstanceFiles(this ILogger logger, string instanceName, string instancePath) + => _deletingInstanceFiles(logger, instanceName, instancePath, null); + + /// + /// Logs that a SQL LocalDB instance's files could not be deleted. + /// + /// The logger to use. + /// The name of the instance whose files could not be deleted. + /// The path of the files that failed to be deleted. + internal static void DeletingInstanceFilesFailed(this ILogger logger, string instanceName, string? instancePath) + => _deletingInstanceFilesFailed(logger, instanceName, instancePath, null); + + /// + /// Logs that information about a SQL LocalDB instance is being retrieved. + /// + /// The logger to use. + /// The name of the instance information is being retrieved for. + internal static void GettingInstanceInfo(this ILogger logger, string instanceName) + => _gettingInstanceInfo(logger, instanceName, null); + + /// + /// Logs that information about a SQL LocalDB instance was retrieved. + /// + /// The logger to use. + /// The name of the instance information was retrieved for. + internal static void GotInstanceInfo(this ILogger logger, string instanceName) + => _gotInstanceInfo(logger, instanceName, null); + + /// + /// Logs that SQL LocalDB instance names are being retrieved. + /// + /// The logger to use. + internal static void GettingInstanceNames(this ILogger logger) + => _gettingInstanceNames(logger, null); + + /// + /// Logs that SQL LocalDB instance names were retrieved. + /// + /// The logger to use. + /// The number of SQL LocalDB instances retrieved. + internal static void GotInstanceNames(this ILogger logger, int count) + => _gotInstanceNames(logger, count, null); + + /// + /// Logs that information about a SQL LocalDB version is being retrieved. + /// + /// The logger to use. + /// The version information is being retrieved for. + internal static void GettingVersionInfo(this ILogger logger, string version) + => _gettingVersionInfo(logger, version, null); + + /// + /// Logs that information about a SQL LocalDB version was retrieved. + /// + /// The logger to use. + /// The version information was retrieved for. + internal static void GotVersionInfo(this ILogger logger, string version) + => _gotVersionInfo(logger, version, null); + + /// + /// Logs that SQL LocalDB versions are being retrieved. + /// + /// The logger to use. + internal static void GettingVersions(this ILogger logger) + => _gettingVersions(logger, null); + + /// + /// Logs that SQL LocalDB versions were retrieved. + /// + /// The logger to use. + /// The number of SQL LocalDB versions retrieved. + internal static void GotVersions(this ILogger logger, int count) + => _gotVersions(logger, count, null); + + /// + /// Logs that an invalid Language Id is configured. + /// + /// The logger to use. + /// The version used. + internal static void InvalidLanguageId(this ILogger logger, int languageId) + => _invalidLanguageId(logger, languageId, null); + + /// + /// Logs that an invalid SQL LocalDB Instance API registry key was found. + /// + /// The logger to use. + /// The version used. + internal static void InvalidRegistryKey(this ILogger logger, string version) + => _invalidRegistryKey(logger, version, null); + + /// + /// Logs that a SQL LocalDB Instance API function could not be found. + /// + /// The logger to use. + /// The name of the function that could not be found. + internal static void NativeApiFunctionNotFound(this ILogger logger, string functionName) + => _nativeApiFunctionNotFound(logger, functionName, null); + + /// + /// Logs that the SQL LocalDB Instance API DLL could not be found at the configured path. + /// + /// The logger to use. + /// The path to the file that could not be found. + internal static void NativeApiLibraryNotFound(this ILogger logger, string path) + => _nativeApiPathNotFound(logger, path, null); + + /// + /// Logs that the SQL LocalDB Instance API DLL was loaded. + /// + /// The logger to use. + /// The full path to the DLL that was loaded. + internal static void NativeApiLoaded(this ILogger logger, string fileName) + => _nativeApiLoaded(logger, fileName, null); + + /// + /// Logs that the SQL LocalDB Instance API DLL could not loaded. + /// + /// The logger to use. + /// The full path to the DLL that could not be loaded. + /// The error code. + internal static void NativeApiLoadFailed(this ILogger logger, string fileName, int error) + => _nativeApiLoadFailed(logger, fileName, error, null); + + /// + /// Logs that the SQL LocalDB Instance API could not be found. + /// + /// The logger to use. + internal static void NativeApiNotFound(this ILogger logger) + => _nativeApiNotFound(logger, null); + + /// + /// Logs that the SQL LocalDB Instance API DLL was not loaded. + /// + /// The logger to use. + internal static void NativeApiNotLoaded(this ILogger logger) + => _nativeApiNotLoaded(logger, null); + + /// + /// Logs that the SQL LocalDB Instance API DLL was unloaded. + /// + /// The logger to use. + /// The full path to the DLL that was unloaded. + internal static void NativeApiUnloaded(this ILogger logger, string fileName) + => _nativeApiUnloaded(logger, fileName, null); + + /// + /// Logs that the version of the SQL LocalDB Instance API to use was overridden by the user. + /// + /// The logger to use. + /// The version used. + internal static void NativeApiVersionOverriddenByUser(this ILogger logger, Version version) + => _nativeApiVersionOverriddenByUser(logger, version, null); + + /// + /// Logs that the version of the SQL LocalDB Instance API specified by the user could not be found. + /// + /// The logger to use. + /// The version specified to be used. + internal static void NativeApiVersionOverrideNotFound(this ILogger logger, string version) + => _nativeApiVersionOverrideNotFound(logger, version, null); + + /// + /// Logs that SQL LocalDB is not installed. + /// + /// The logger to use. + internal static void NotInstalled(this ILogger logger) + => _notInstalled(logger, null); + + /// + /// Logs that the SQL LocalDB Instance API registry key cannot be found. + /// + /// The logger to use. + /// The name of the registry key that was not found. + internal static void RegistryKeyNotFound(this ILogger logger, string keyName) + => _registryKeyNotFound(logger, keyName, null); + + /// + /// Logs that a SQL LocalDB instance is being shared. + /// + /// The logger to use. + /// The name of the instance that is being shared. + /// The SID of the instance owner. + /// The shared name for the LocalDB instance to share as. + internal static void SharingInstance(this ILogger logger, string instanceName, string ownerSid, string sharedInstanceName) + => _sharingInstance(logger, instanceName, ownerSid, sharedInstanceName, null); + + /// + /// Logs that a SQL LocalDB instance was shared. + /// + /// The logger to use. + /// The name of the instance that was shared. + /// The SID of the instance owner. + /// The shared name for the LocalDB instance to share as. + internal static void SharedInstance(this ILogger logger, string instanceName, string ownerSid, string sharedInstanceName) + => _sharedInstance(logger, instanceName, ownerSid, sharedInstanceName, null); + + /// + /// Logs that a SQL LocalDB instance was started. + /// + /// The logger to use. + /// The name of the instance that was started. + /// The named pipe the instance is listening on. + internal static void StartedInstance(this ILogger logger, string instanceName, string namedPipe) + => _startedInstance(logger, instanceName, namedPipe, null); + + /// + /// Logs that a SQL LocalDB instance is starting. + /// + /// The logger to use. + /// The name of the instance that is starting. + internal static void StartingInstance(this ILogger logger, string instanceName) + => _startingInstance(logger, instanceName, null); + + /// + /// Logs that SQL LocalDB tracing was started. + /// + /// The logger to use. + internal static void StartedTracing(this ILogger logger) + => _startedTracing(logger, null); + + /// + /// Logs that SQL LocalDB tracing is starting. + /// + /// The logger to use. + internal static void StartingTracing(this ILogger logger) + => _startingTracing(logger, null); + + /// + /// Logs that a SQL LocalDB instance was stopped. + /// + /// The logger to use. + /// The name of the instance that was stopped. + /// The time taken for the instance to stop. + internal static void StoppedInstance(this ILogger logger, string instanceName, TimeSpan elapsed) + => _stoppedInstance(logger, instanceName, elapsed, null); + + /// + /// Logs that a SQL LocalDB instance is stopping. + /// + /// The logger to use. + /// The name of the instance that is stopping. + /// The timeout used. + /// The stop options used. + internal static void StoppingInstance(this ILogger logger, string instanceName, TimeSpan timeout, StopInstanceOptions options) + => _stoppingInstance(logger, instanceName, timeout, options, null); + + /// + /// Logs that a temporary SQL LocalDB instance failed to stop. + /// + /// The logger to use. + /// The name of the instance that failed to stop. + /// The error code. + internal static void StoppingTemporaryInstanceFailed(this ILogger logger, string instanceName, int error) + => _stoppingTemporaryInstanceFailed(logger, instanceName, error.ToString("X", CultureInfo.InvariantCulture), null); + + /// + /// Logs that SQL LocalDB tracing was stopped. + /// + /// The logger to use. + internal static void StoppedTracing(this ILogger logger) + => _stoppedTracing(logger, null); + + /// + /// Logs that SQL LocalDB tracing is stopping. + /// + /// The logger to use. + internal static void StoppingTracing(this ILogger logger) + => _stoppingTracing(logger, null); + + /// + /// Logs that a SQL LocalDB instance is being unshared. + /// + /// The logger to use. + /// The name of the instance that is being shared. + internal static void UnsharingInstance(this ILogger logger, string instanceName) + => _unsharingInstance(logger, instanceName, null); + + /// + /// Logs that a SQL LocalDB instance was shared. + /// + /// The logger to use. + /// The name of the instance that was shared. + internal static void UnsharedInstance(this ILogger logger, string instanceName) + => _unsharedInstance(logger, instanceName, null); } diff --git a/src/SqlLocalDb/ISqlLocalDbApi.cs b/src/SqlLocalDb/ISqlLocalDbApi.cs index d82b5cd8..ba68d7be 100644 --- a/src/SqlLocalDb/ISqlLocalDbApi.cs +++ b/src/SqlLocalDb/ISqlLocalDbApi.cs @@ -1,143 +1,139 @@ -// Copyright (c) Martin Costello, 2012-2018. All rights reserved. +// Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -using System; -using System.Collections.Generic; +namespace MartinCostello.SqlLocalDb; -namespace MartinCostello.SqlLocalDb +/// +/// Defines the interface to the SQL LocalDB Instance API. +/// +public interface ISqlLocalDbApi { /// - /// Defines the interface to the SQL LocalDB Instance API. - /// - public interface ISqlLocalDbApi - { - /// - /// Gets the name of the default SQL LocalDB instance. - /// - string DefaultInstanceName { get; } - - /// - /// Gets the version string for the latest installed version of SQL Server LocalDB. - /// - string LatestVersion { get; } - - /// - /// Gets an of containing the available version(s) of SQL LocalDB. - /// - IReadOnlyList Versions { get; } - - /// - /// Creates a new instance of SQL Server LocalDB. - /// - /// The name of the LocalDB instance. - /// The version of SQL Server LocalDB to use. - /// - /// An containing information about the instance that was created. - /// - ISqlLocalDbInstanceInfo CreateInstance(string instanceName, string version); - - /// - /// Deletes the specified SQL Server LocalDB instance. - /// - /// - /// The name of the LocalDB instance to delete. - /// - void DeleteInstance(string instanceName); - - /// - /// Returns information about the specified LocalDB instance. - /// - /// The name of the LocalDB instance to get the information for. - /// - /// An instance of containing information - /// about the LocalDB instance specified by . - /// - ISqlLocalDbInstanceInfo GetInstanceInfo(string instanceName); - - /// - /// Returns the names of all the SQL Server LocalDB instances for the current user. - /// - /// - /// The names of the the SQL Server LocalDB instances for the current user. - /// - IReadOnlyList GetInstanceNames(); - - /// - /// Returns information about the specified LocalDB version. - /// - /// The name of the LocalDB version to get the information for. - /// - /// An instance of containing information - /// about the LocalDB version specified by . - /// - ISqlLocalDbVersionInfo GetVersionInfo(string version); - - /// - /// Returns whether the specified LocalDB instance exists. - /// - /// The name of the LocalDB instance to check for existence. - /// - /// if the LocalDB instance specified by - /// exists; otherwise . - /// - bool InstanceExists(string instanceName); - - /// - /// Returns whether SQL LocalDB is installed on the current machine. - /// - /// - /// if SQL Server LocalDB is installed on the - /// current machine; otherwise . - /// - bool IsLocalDBInstalled(); - - /// - /// Shares the specified SQL Server LocalDB instance with other - /// users of the computer, using the specified shared name. - /// - /// The SID of the instance owner. - /// The private name for the LocalDB instance to share. - /// The shared name for the LocalDB instance to share. - void ShareInstance(string ownerSid, string instanceName, string sharedInstanceName); - - /// - /// Starts the specified instance of SQL Server LocalDB. - /// - /// The name of the LocalDB instance to start. - /// - /// The named pipe to use to connect to the LocalDB instance. - /// - string StartInstance(string instanceName); - - /// - /// Enables tracing of native API calls for all the SQL Server - /// LocalDB instances owned by the current Windows user. - /// - void StartTracing(); - - /// - /// Stops the specified instance of SQL Server LocalDB. - /// - /// - /// The name of the LocalDB instance to stop. - /// - /// - /// The optional amount of time to give the LocalDB instance to stop. - /// - void StopInstance(string instanceName, TimeSpan? timeout); - - /// - /// Disables tracing of native API calls for all the SQL Server - /// LocalDB instances owned by the current Windows user. - /// - void StopTracing(); - - /// - /// Stops the sharing of the specified SQL Server LocalDB instance. - /// - /// - /// The private name for the LocalDB instance to stop sharing. - /// - void UnshareInstance(string instanceName); - } + /// Gets the name of the default SQL LocalDB instance. + /// + string DefaultInstanceName { get; } + + /// + /// Gets the version string for the latest installed version of SQL Server LocalDB. + /// + string LatestVersion { get; } + + /// + /// Gets an of containing the available version(s) of SQL LocalDB. + /// + IReadOnlyList Versions { get; } + + /// + /// Creates a new instance of SQL Server LocalDB. + /// + /// The name of the LocalDB instance. + /// The version of SQL Server LocalDB to use. + /// + /// An containing information about the instance that was created. + /// + ISqlLocalDbInstanceInfo CreateInstance(string instanceName, string version); + + /// + /// Deletes the specified SQL Server LocalDB instance. + /// + /// + /// The name of the LocalDB instance to delete. + /// + void DeleteInstance(string instanceName); + + /// + /// Returns information about the specified LocalDB instance. + /// + /// The name of the LocalDB instance to get the information for. + /// + /// An instance of containing information + /// about the LocalDB instance specified by . + /// + ISqlLocalDbInstanceInfo GetInstanceInfo(string instanceName); + + /// + /// Returns the names of all the SQL Server LocalDB instances for the current user. + /// + /// + /// The names of the the SQL Server LocalDB instances for the current user. + /// + IReadOnlyList GetInstanceNames(); + + /// + /// Returns information about the specified LocalDB version. + /// + /// The name of the LocalDB version to get the information for. + /// + /// An instance of containing information + /// about the LocalDB version specified by . + /// + ISqlLocalDbVersionInfo GetVersionInfo(string version); + + /// + /// Returns whether the specified LocalDB instance exists. + /// + /// The name of the LocalDB instance to check for existence. + /// + /// if the LocalDB instance specified by + /// exists; otherwise . + /// + bool InstanceExists(string instanceName); + + /// + /// Returns whether SQL LocalDB is installed on the current machine. + /// + /// + /// if SQL Server LocalDB is installed on the + /// current machine; otherwise . + /// + bool IsLocalDBInstalled(); + + /// + /// Shares the specified SQL Server LocalDB instance with other + /// users of the computer, using the specified shared name. + /// + /// The SID of the instance owner. + /// The private name for the LocalDB instance to share. + /// The shared name for the LocalDB instance to share. + void ShareInstance(string ownerSid, string instanceName, string sharedInstanceName); + + /// + /// Starts the specified instance of SQL Server LocalDB. + /// + /// The name of the LocalDB instance to start. + /// + /// The named pipe to use to connect to the LocalDB instance. + /// + string StartInstance(string instanceName); + + /// + /// Enables tracing of native API calls for all the SQL Server + /// LocalDB instances owned by the current Windows user. + /// + void StartTracing(); + + /// + /// Stops the specified instance of SQL Server LocalDB. + /// + /// + /// The name of the LocalDB instance to stop. + /// + /// + /// The optional amount of time to give the LocalDB instance to stop. + /// + void StopInstance(string instanceName, TimeSpan? timeout); + + /// + /// Disables tracing of native API calls for all the SQL Server + /// LocalDB instances owned by the current Windows user. + /// + void StopTracing(); + + /// + /// Stops the sharing of the specified SQL Server LocalDB instance. + /// + /// + /// The private name for the LocalDB instance to stop sharing. + /// + void UnshareInstance(string instanceName); } diff --git a/src/SqlLocalDb/ISqlLocalDbApiAdapter.cs b/src/SqlLocalDb/ISqlLocalDbApiAdapter.cs index 51fb7237..2d7efe2f 100644 --- a/src/SqlLocalDb/ISqlLocalDbApiAdapter.cs +++ b/src/SqlLocalDb/ISqlLocalDbApiAdapter.cs @@ -1,16 +1,15 @@ // Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -namespace MartinCostello.SqlLocalDb +namespace MartinCostello.SqlLocalDb; + +/// +/// Defines an interface implemented by objects that can provide an instance. +/// +public interface ISqlLocalDbApiAdapter { /// - /// Defines an interface implemented by objects that can provide an instance. + /// Gets the instance. /// - public interface ISqlLocalDbApiAdapter - { - /// - /// Gets the instance. - /// - ISqlLocalDbApi LocalDb { get; } - } + ISqlLocalDbApi LocalDb { get; } } diff --git a/src/SqlLocalDb/ISqlLocalDbApiExtensions.cs b/src/SqlLocalDb/ISqlLocalDbApiExtensions.cs index cf118052..40689cb0 100644 --- a/src/SqlLocalDb/ISqlLocalDbApiExtensions.cs +++ b/src/SqlLocalDb/ISqlLocalDbApiExtensions.cs @@ -6,199 +6,198 @@ using System.ComponentModel; using System.Security.Principal; -namespace MartinCostello.SqlLocalDb +namespace MartinCostello.SqlLocalDb; + +/// +/// A class containing extension methods for the interface. This class cannot be inherited. +/// +[EditorBrowsable(EditorBrowsableState.Never)] +public static class ISqlLocalDbApiExtensions { /// - /// A class containing extension methods for the interface. This class cannot be inherited. + /// Creates a new instance of with a randomly assigned name. + /// + /// The to use to create the temporary instance. + /// An optional value indicating whether to delete the file(s) associated with the SQL LocalDB instance when it is deleted. + /// + /// The created instance of . + /// + /// + /// is . + /// + public static TemporarySqlLocalDbInstance CreateTemporaryInstance(this ISqlLocalDbApi api, bool deleteFiles = false) + => new TemporarySqlLocalDbInstance(api, deleteFiles); + + /// + /// Gets the default SQL Local DB instance. /// - [EditorBrowsable(EditorBrowsableState.Never)] - public static class ISqlLocalDbApiExtensions + /// The to use to get the default instance. + /// + /// The default SQL Local DB instance. + /// + /// + /// is . + /// + public static ISqlLocalDbInstanceInfo GetDefaultInstance(this ISqlLocalDbApi api) { - /// - /// Creates a new instance of with a randomly assigned name. - /// - /// The to use to create the temporary instance. - /// An optional value indicating whether to delete the file(s) associated with the SQL LocalDB instance when it is deleted. - /// - /// The created instance of . - /// - /// - /// is . - /// - public static TemporarySqlLocalDbInstance CreateTemporaryInstance(this ISqlLocalDbApi api, bool deleteFiles = false) - => new TemporarySqlLocalDbInstance(api, deleteFiles); - - /// - /// Gets the default SQL Local DB instance. - /// - /// The to use to get the default instance. - /// - /// The default SQL Local DB instance. - /// - /// - /// is . - /// - public static ISqlLocalDbInstanceInfo GetDefaultInstance(this ISqlLocalDbApi api) + if (api == null) { - if (api == null) - { - throw new ArgumentNullException(nameof(api)); - } - - return api.GetOrCreateInstance(api.DefaultInstanceName); + throw new ArgumentNullException(nameof(api)); } - /// - /// Returns information about the available SQL Server LocalDB instances. - /// - /// The to use to enumerate the instances. - /// - /// An containing information - /// about the available SQL Server LocalDB instances on the current machine. - /// - /// - /// is . - /// - public static IReadOnlyList GetInstances(this ISqlLocalDbApi api) + return api.GetOrCreateInstance(api.DefaultInstanceName); + } + + /// + /// Returns information about the available SQL Server LocalDB instances. + /// + /// The to use to enumerate the instances. + /// + /// An containing information + /// about the available SQL Server LocalDB instances on the current machine. + /// + /// + /// is . + /// + public static IReadOnlyList GetInstances(this ISqlLocalDbApi api) + { + if (api == null) { - if (api == null) - { - throw new ArgumentNullException(nameof(api)); - } + throw new ArgumentNullException(nameof(api)); + } - IReadOnlyList instanceNames = api.GetInstanceNames(); + IReadOnlyList instanceNames = api.GetInstanceNames(); - var instances = new List(instanceNames?.Count ?? 0); + var instances = new List(instanceNames?.Count ?? 0); - if (instanceNames != null) + if (instanceNames != null) + { + foreach (string name in instanceNames) { - foreach (string name in instanceNames) - { - ISqlLocalDbInstanceInfo info = api.GetInstanceInfo(name); - instances.Add(info); - } + ISqlLocalDbInstanceInfo info = api.GetInstanceInfo(name); + instances.Add(info); } - - return instances; } - /// - /// Returns information about the installed SQL Server LocalDB version(s). - /// - /// The to use to enumerate the installed versions. - /// - /// An containing information - /// about the SQL Server LocalDB version(s) installed on the current machine. - /// - /// - /// is . - /// - public static IReadOnlyList GetVersions(this ISqlLocalDbApi api) + return instances; + } + + /// + /// Returns information about the installed SQL Server LocalDB version(s). + /// + /// The to use to enumerate the installed versions. + /// + /// An containing information + /// about the SQL Server LocalDB version(s) installed on the current machine. + /// + /// + /// is . + /// + public static IReadOnlyList GetVersions(this ISqlLocalDbApi api) + { + if (api == null) { - if (api == null) - { - throw new ArgumentNullException(nameof(api)); - } + throw new ArgumentNullException(nameof(api)); + } - IReadOnlyList versionNames = api.Versions; - var versions = new List(versionNames?.Count ?? 0); + IReadOnlyList versionNames = api.Versions; + var versions = new List(versionNames?.Count ?? 0); - if (versionNames != null) + if (versionNames != null) + { + foreach (string version in versionNames) { - foreach (string version in versionNames) - { - ISqlLocalDbVersionInfo info = api.GetVersionInfo(version); - versions.Add(info); - } + ISqlLocalDbVersionInfo info = api.GetVersionInfo(version); + versions.Add(info); } + } + + return versions; + } - return versions; + /// + /// Gets a SQL Local DB instance with the specified name if it exists, otherwise a new instance with the specified name is created. + /// + /// The to use to get or create the instance. + /// The name of the SQL Server LocalDB instance to get or create. + /// + /// A SQL Local DB instance with the name specified by . + /// + /// + /// or is . + /// + public static ISqlLocalDbInstanceInfo GetOrCreateInstance(this ISqlLocalDbApi api, string instanceName) + { + if (api == null) + { + throw new ArgumentNullException(nameof(api)); } - /// - /// Gets a SQL Local DB instance with the specified name if it exists, otherwise a new instance with the specified name is created. - /// - /// The to use to get or create the instance. - /// The name of the SQL Server LocalDB instance to get or create. - /// - /// A SQL Local DB instance with the name specified by . - /// - /// - /// or is . - /// - public static ISqlLocalDbInstanceInfo GetOrCreateInstance(this ISqlLocalDbApi api, string instanceName) + if (instanceName == null) { - if (api == null) - { - throw new ArgumentNullException(nameof(api)); - } + throw new ArgumentNullException(nameof(instanceName)); + } - if (instanceName == null) - { - throw new ArgumentNullException(nameof(instanceName)); - } + // Instance names in SQL Local DB are case-insensitive + if (string.Equals(api.DefaultInstanceName, instanceName, StringComparison.OrdinalIgnoreCase) || + SqlLocalDbApi.IsDefaultInstanceName(instanceName)) + { + // The default instance is always listed, even if it does not exist, + // so need to query that separately to verify whether to get or create. + ISqlLocalDbInstanceInfo info = api.GetInstanceInfo(instanceName); - // Instance names in SQL Local DB are case-insensitive - if (string.Equals(api.DefaultInstanceName, instanceName, StringComparison.OrdinalIgnoreCase) || - SqlLocalDbApi.IsDefaultInstanceName(instanceName)) + if (info != null) { - // The default instance is always listed, even if it does not exist, - // so need to query that separately to verify whether to get or create. - ISqlLocalDbInstanceInfo info = api.GetInstanceInfo(instanceName); - - if (info != null) + // If it exists (or it's a default instance), we can't create + // it so just return the information about it immediately. + if (info.Exists || info.IsAutomatic) { - // If it exists (or it's a default instance), we can't create - // it so just return the information about it immediately. - if (info.Exists || info.IsAutomatic) - { - return info; - } + return info; } } + } - if (api.InstanceExists(instanceName)) - { - return api.GetInstanceInfo(instanceName); - } - else - { - return api.CreateInstance(instanceName, api.LatestVersion); - } + if (api.InstanceExists(instanceName)) + { + return api.GetInstanceInfo(instanceName); + } + else + { + return api.CreateInstance(instanceName, api.LatestVersion); } + } - /// - /// Shares the specified SQL Server LocalDB instance with other users of the computer, - /// using the specified shared name for the current Windows user. - /// - /// The to use to share the instance. - /// The private name for the LocalDB instance to share. - /// The shared name for the LocalDB instance to share. - /// - /// , or is . - /// - /// - /// The method is called from a non-Windows operating system. - /// - public static void ShareInstance(this ISqlLocalDbApi api, string instanceName, string sharedInstanceName) + /// + /// Shares the specified SQL Server LocalDB instance with other users of the computer, + /// using the specified shared name for the current Windows user. + /// + /// The to use to share the instance. + /// The private name for the LocalDB instance to share. + /// The shared name for the LocalDB instance to share. + /// + /// , or is . + /// + /// + /// The method is called from a non-Windows operating system. + /// + public static void ShareInstance(this ISqlLocalDbApi api, string instanceName, string sharedInstanceName) + { + if (api == null) { - if (api == null) - { - throw new ArgumentNullException(nameof(api)); - } + throw new ArgumentNullException(nameof(api)); + } - SqlLocalDbApi.EnsurePlatformSupported(); + SqlLocalDbApi.EnsurePlatformSupported(); - string ownerSid; + string ownerSid; #pragma warning disable CA1416 - using (var identity = WindowsIdentity.GetCurrent()) - { - ownerSid = identity.User!.Value; - } + using (var identity = WindowsIdentity.GetCurrent()) + { + ownerSid = identity.User!.Value; + } #pragma warning restore CA1416 - api.ShareInstance(ownerSid, instanceName, sharedInstanceName); - } + api.ShareInstance(ownerSid, instanceName, sharedInstanceName); } } diff --git a/src/SqlLocalDb/ISqlLocalDbInstanceInfo.cs b/src/SqlLocalDb/ISqlLocalDbInstanceInfo.cs index 5f645659..3b59607a 100644 --- a/src/SqlLocalDb/ISqlLocalDbInstanceInfo.cs +++ b/src/SqlLocalDb/ISqlLocalDbInstanceInfo.cs @@ -1,66 +1,65 @@ // Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -namespace MartinCostello.SqlLocalDb +namespace MartinCostello.SqlLocalDb; + +/// +/// Defines information about a SQL Server LocalDB instance. +/// +public interface ISqlLocalDbInstanceInfo { /// - /// Defines information about a SQL Server LocalDB instance. + /// Gets a value indicating whether the Registry configuration is corrupt. /// - public interface ISqlLocalDbInstanceInfo - { - /// - /// Gets a value indicating whether the Registry configuration is corrupt. - /// - bool ConfigurationCorrupt { get; } + bool ConfigurationCorrupt { get; } - /// - /// Gets a value indicating whether the instance's files exist on disk. - /// - bool Exists { get; } + /// + /// Gets a value indicating whether the instance's files exist on disk. + /// + bool Exists { get; } - /// - /// Gets a value indicating whether the instance is automatic. - /// - bool IsAutomatic { get; } + /// + /// Gets a value indicating whether the instance is automatic. + /// + bool IsAutomatic { get; } - /// - /// Gets a value indicating whether the instance is currently running. - /// - bool IsRunning { get; } + /// + /// Gets a value indicating whether the instance is currently running. + /// + bool IsRunning { get; } - /// - /// Gets a value indicating whether the instance is shared. - /// - bool IsShared { get; } + /// + /// Gets a value indicating whether the instance is shared. + /// + bool IsShared { get; } - /// - /// Gets the UTC date and time the instance was last started. - /// - DateTime LastStartTimeUtc { get; } + /// + /// Gets the UTC date and time the instance was last started. + /// + DateTime LastStartTimeUtc { get; } - /// - /// Gets the LocalDB version for the instance. - /// - Version LocalDbVersion { get; } + /// + /// Gets the LocalDB version for the instance. + /// + Version LocalDbVersion { get; } - /// - /// Gets the name of the instance. - /// - string Name { get; } + /// + /// Gets the name of the instance. + /// + string Name { get; } - /// - /// Gets the named pipe that should be used to communicate with the instance. - /// - string NamedPipe { get; } + /// + /// Gets the named pipe that should be used to communicate with the instance. + /// + string NamedPipe { get; } - /// - /// Gets the SID of the LocalDB instance owner if the instance is shared. - /// - string OwnerSid { get; } + /// + /// Gets the SID of the LocalDB instance owner if the instance is shared. + /// + string OwnerSid { get; } - /// - /// Gets the shared name of the LocalDB instance if the instance is shared. - /// - string SharedName { get; } - } + /// + /// Gets the shared name of the LocalDB instance if the instance is shared. + /// + string SharedName { get; } } diff --git a/src/SqlLocalDb/ISqlLocalDbInstanceInfoExtensions.cs b/src/SqlLocalDb/ISqlLocalDbInstanceInfoExtensions.cs index 49c993b0..50fbdbb0 100644 --- a/src/SqlLocalDb/ISqlLocalDbInstanceInfoExtensions.cs +++ b/src/SqlLocalDb/ISqlLocalDbInstanceInfoExtensions.cs @@ -4,114 +4,113 @@ using System.ComponentModel; using Microsoft.Data.SqlClient; -namespace MartinCostello.SqlLocalDb +namespace MartinCostello.SqlLocalDb; + +/// +/// A class containing extension methods for the interface. This class cannot be inherited. +/// +[EditorBrowsable(EditorBrowsableState.Never)] +public static class ISqlLocalDbInstanceInfoExtensions { /// - /// A class containing extension methods for the interface. This class cannot be inherited. + /// Creates a connection to the LocalDB instance. + /// + /// The SQL LocalDB instance to create a connection to. + /// + /// An instance of that can be used to connect to the LocalDB instance. + /// + /// + /// is . + /// + /// + /// The SQL LocalDB instance specified by is not running. + /// + public static SqlConnection CreateConnection(this ISqlLocalDbInstanceInfo instance) + { + SqlConnectionStringBuilder builder = instance.CreateConnectionStringBuilder(); + return new SqlConnection(builder.ConnectionString); + } + + /// + /// Creates an instance of containing + /// the default SQL connection string to connect to the LocalDB instance. /// - [EditorBrowsable(EditorBrowsableState.Never)] - public static class ISqlLocalDbInstanceInfoExtensions + /// The SQL LocalDB instance to create a connection string builder for. + /// + /// An instance of containing + /// the default SQL connection string to connect to the LocalDB instance. + /// + /// + /// is . + /// + /// + /// The SQL LocalDB instance specified by is not running. + /// + public static SqlConnectionStringBuilder CreateConnectionStringBuilder(this ISqlLocalDbInstanceInfo instance) { - /// - /// Creates a connection to the LocalDB instance. - /// - /// The SQL LocalDB instance to create a connection to. - /// - /// An instance of that can be used to connect to the LocalDB instance. - /// - /// - /// is . - /// - /// - /// The SQL LocalDB instance specified by is not running. - /// - public static SqlConnection CreateConnection(this ISqlLocalDbInstanceInfo instance) + if (instance == null) { - SqlConnectionStringBuilder builder = instance.CreateConnectionStringBuilder(); - return new SqlConnection(builder.ConnectionString); + throw new ArgumentNullException(nameof(instance)); } - /// - /// Creates an instance of containing - /// the default SQL connection string to connect to the LocalDB instance. - /// - /// The SQL LocalDB instance to create a connection string builder for. - /// - /// An instance of containing - /// the default SQL connection string to connect to the LocalDB instance. - /// - /// - /// is . - /// - /// - /// The SQL LocalDB instance specified by is not running. - /// - public static SqlConnectionStringBuilder CreateConnectionStringBuilder(this ISqlLocalDbInstanceInfo instance) + if (!instance.IsRunning) { - if (instance == null) - { - throw new ArgumentNullException(nameof(instance)); - } - - if (!instance.IsRunning) - { - string message = SRHelper.Format(SR.ISqlLocalDbInstanceInfoExtensions_NotRunningFormat, instance.Name); - throw new InvalidOperationException(message); - } - - return new SqlConnectionStringBuilder() - { - DataSource = instance.NamedPipe, - }; + string message = SRHelper.Format(SR.ISqlLocalDbInstanceInfoExtensions_NotRunningFormat, instance.Name); + throw new InvalidOperationException(message); } - /// - /// Gets the default SQL connection string to connect to the LocalDB instance. - /// - /// The SQL LocalDB instance to get the default connection string for. - /// - /// The default SQL connection string to connect to the LocalDB instance. - /// - /// - /// is . - /// - /// - /// The SQL LocalDB instance specified by is not running. - /// - public static string GetConnectionString(this ISqlLocalDbInstanceInfo instance) - => instance.CreateConnectionStringBuilder().ConnectionString; - - /// - /// Returns an that can be used to manage the instance. - /// - /// The to manage. - /// - /// An that can be used to manage the SQL LocalDB instance. - /// - /// - /// is . - /// - /// - /// does not implement . - /// - public static ISqlLocalDbInstanceManager Manage(this ISqlLocalDbInstanceInfo instance) + return new SqlConnectionStringBuilder() { - if (instance == null) - { - throw new ArgumentNullException(nameof(instance)); - } + DataSource = instance.NamedPipe, + }; + } - if (instance is ISqlLocalDbApiAdapter adapter) - { - return new SqlLocalDbInstanceManager(instance, adapter.LocalDb); - } + /// + /// Gets the default SQL connection string to connect to the LocalDB instance. + /// + /// The SQL LocalDB instance to get the default connection string for. + /// + /// The default SQL connection string to connect to the LocalDB instance. + /// + /// + /// is . + /// + /// + /// The SQL LocalDB instance specified by is not running. + /// + public static string GetConnectionString(this ISqlLocalDbInstanceInfo instance) + => instance.CreateConnectionStringBuilder().ConnectionString; - string message = SRHelper.Format( - SR.ISqlLocalDbInstanceInfoExtensions_DoesNotImplementAdapterFormat, - nameof(ISqlLocalDbInstanceInfo), - nameof(ISqlLocalDbApiAdapter)); + /// + /// Returns an that can be used to manage the instance. + /// + /// The to manage. + /// + /// An that can be used to manage the SQL LocalDB instance. + /// + /// + /// is . + /// + /// + /// does not implement . + /// + public static ISqlLocalDbInstanceManager Manage(this ISqlLocalDbInstanceInfo instance) + { + if (instance == null) + { + throw new ArgumentNullException(nameof(instance)); + } - throw new ArgumentException(message, nameof(instance)); + if (instance is ISqlLocalDbApiAdapter adapter) + { + return new SqlLocalDbInstanceManager(instance, adapter.LocalDb); } + + string message = SRHelper.Format( + SR.ISqlLocalDbInstanceInfoExtensions_DoesNotImplementAdapterFormat, + nameof(ISqlLocalDbInstanceInfo), + nameof(ISqlLocalDbApiAdapter)); + + throw new ArgumentException(message, nameof(instance)); } } diff --git a/src/SqlLocalDb/ISqlLocalDbInstanceManager.cs b/src/SqlLocalDb/ISqlLocalDbInstanceManager.cs index 7923851f..1138fc44 100644 --- a/src/SqlLocalDb/ISqlLocalDbInstanceManager.cs +++ b/src/SqlLocalDb/ISqlLocalDbInstanceManager.cs @@ -1,52 +1,51 @@ // Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -namespace MartinCostello.SqlLocalDb +namespace MartinCostello.SqlLocalDb; + +/// +/// Defines an interface for managing instances of SQL LocalDB. +/// +public interface ISqlLocalDbInstanceManager { /// - /// Defines an interface for managing instances of SQL LocalDB. + /// Gets the name of the LocalDB instance. + /// + string Name { get; } + + /// + /// Gets the named pipe that should be used to connect to the LocalDB instance. + /// + string NamedPipe { get; } + + /// + /// Gets the current state of the instance. + /// + /// + /// An representing the current state of the instance being managed. + /// + ISqlLocalDbInstanceInfo GetInstanceInfo(); + + /// + /// Shares the LocalDB instance using the specified name. + /// + /// The name to use to share the instance. + void Share(string sharedName); + + /// + /// Starts the LocalDB instance. + /// + void Start(); + + /// + /// Stops the LocalDB instance. /// - public interface ISqlLocalDbInstanceManager - { - /// - /// Gets the name of the LocalDB instance. - /// - string Name { get; } - - /// - /// Gets the named pipe that should be used to connect to the LocalDB instance. - /// - string NamedPipe { get; } - - /// - /// Gets the current state of the instance. - /// - /// - /// An representing the current state of the instance being managed. - /// - ISqlLocalDbInstanceInfo GetInstanceInfo(); - - /// - /// Shares the LocalDB instance using the specified name. - /// - /// The name to use to share the instance. - void Share(string sharedName); - - /// - /// Starts the LocalDB instance. - /// - void Start(); - - /// - /// Stops the LocalDB instance. - /// #pragma warning disable CA1716 // Identifiers should not match keywords - void Stop(); + void Stop(); #pragma warning restore CA1716 // Identifiers should not match keywords - /// - /// Stops sharing the LocalDB instance. - /// - void Unshare(); - } + /// + /// Stops sharing the LocalDB instance. + /// + void Unshare(); } diff --git a/src/SqlLocalDb/ISqlLocalDbInstanceManagerExtensions.cs b/src/SqlLocalDb/ISqlLocalDbInstanceManagerExtensions.cs index 0f2cccdb..03cf3de1 100644 --- a/src/SqlLocalDb/ISqlLocalDbInstanceManagerExtensions.cs +++ b/src/SqlLocalDb/ISqlLocalDbInstanceManagerExtensions.cs @@ -4,50 +4,49 @@ using System.ComponentModel; using Microsoft.Data.SqlClient; -namespace MartinCostello.SqlLocalDb +namespace MartinCostello.SqlLocalDb; + +/// +/// A class containing extension methods for the interface. This class cannot be inherited. +/// +[EditorBrowsable(EditorBrowsableState.Never)] +public static class ISqlLocalDbInstanceManagerExtensions { /// - /// A class containing extension methods for the interface. This class cannot be inherited. + /// Creates a connection to the LocalDB instance. /// - [EditorBrowsable(EditorBrowsableState.Never)] - public static class ISqlLocalDbInstanceManagerExtensions + /// The associated with the instance to create a connection to. + /// + /// An instance of that can be used to connect to the LocalDB instance. + /// + /// + /// is . + /// + public static SqlConnection CreateConnection(this ISqlLocalDbInstanceManager manager) { - /// - /// Creates a connection to the LocalDB instance. - /// - /// The associated with the instance to create a connection to. - /// - /// An instance of that can be used to connect to the LocalDB instance. - /// - /// - /// is . - /// - public static SqlConnection CreateConnection(this ISqlLocalDbInstanceManager manager) + if (manager == null) { - if (manager == null) - { - throw new ArgumentNullException(nameof(manager)); - } - - return manager.GetInstanceInfo().CreateConnection(); + throw new ArgumentNullException(nameof(manager)); } - /// - /// Restarts the specified instance. - /// - /// The associated with the instance to restart. - /// - /// is . - /// - public static void Restart(this ISqlLocalDbInstanceManager manager) - { - if (manager == null) - { - throw new ArgumentNullException(nameof(manager)); - } + return manager.GetInstanceInfo().CreateConnection(); + } - manager.Stop(); - manager.Start(); + /// + /// Restarts the specified instance. + /// + /// The associated with the instance to restart. + /// + /// is . + /// + public static void Restart(this ISqlLocalDbInstanceManager manager) + { + if (manager == null) + { + throw new ArgumentNullException(nameof(manager)); } + + manager.Stop(); + manager.Start(); } } diff --git a/src/SqlLocalDb/ISqlLocalDbVersionInfo.cs b/src/SqlLocalDb/ISqlLocalDbVersionInfo.cs index c8a9367c..16af2a18 100644 --- a/src/SqlLocalDb/ISqlLocalDbVersionInfo.cs +++ b/src/SqlLocalDb/ISqlLocalDbVersionInfo.cs @@ -1,26 +1,25 @@ // Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -namespace MartinCostello.SqlLocalDb +namespace MartinCostello.SqlLocalDb; + +/// +/// Defines information about a version of SQL Server LocalDB. +/// +public interface ISqlLocalDbVersionInfo { /// - /// Defines information about a version of SQL Server LocalDB. + /// Gets a value indicating whether the instance files exist on disk. /// - public interface ISqlLocalDbVersionInfo - { - /// - /// Gets a value indicating whether the instance files exist on disk. - /// - bool Exists { get; } + bool Exists { get; } - /// - /// Gets the version name. - /// - string Name { get; } + /// + /// Gets the version name. + /// + string Name { get; } - /// - /// Gets the version. - /// - Version Version { get; } - } + /// + /// Gets the version. + /// + Version Version { get; } } diff --git a/src/SqlLocalDb/Interop/IRegistry.cs b/src/SqlLocalDb/Interop/IRegistry.cs index 68579681..c1011198 100644 --- a/src/SqlLocalDb/Interop/IRegistry.cs +++ b/src/SqlLocalDb/Interop/IRegistry.cs @@ -1,20 +1,19 @@ // Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -namespace MartinCostello.SqlLocalDb.Interop +namespace MartinCostello.SqlLocalDb.Interop; + +/// +/// Defines a method for opening a registry sub-key. +/// +internal interface IRegistry { /// - /// Defines a method for opening a registry sub-key. + /// Retrieves a sub-key as read-only. /// - internal interface IRegistry - { - /// - /// Retrieves a sub-key as read-only. - /// - /// The name or path of the sub-key to open as read-only. - /// - /// The sub-key requested, or if the operation failed. - /// - IRegistryKey? OpenSubKey(string keyName); - } + /// The name or path of the sub-key to open as read-only. + /// + /// The sub-key requested, or if the operation failed. + /// + IRegistryKey? OpenSubKey(string keyName); } diff --git a/src/SqlLocalDb/Interop/IRegistryKey.cs b/src/SqlLocalDb/Interop/IRegistryKey.cs index cbe3e399..f6c3de8e 100644 --- a/src/SqlLocalDb/Interop/IRegistryKey.cs +++ b/src/SqlLocalDb/Interop/IRegistryKey.cs @@ -1,28 +1,27 @@ // Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -namespace MartinCostello.SqlLocalDb.Interop +namespace MartinCostello.SqlLocalDb.Interop; + +/// +/// Defines a registry sub-key. +/// +internal interface IRegistryKey : IRegistry, IDisposable { /// - /// Defines a registry sub-key. + /// Retrieves an array of strings that contains all the sub-key names. /// - internal interface IRegistryKey : IRegistry, IDisposable - { - /// - /// Retrieves an array of strings that contains all the sub-key names. - /// - /// - /// An array of strings that contains the names of the sub-keys for the current key. - /// - string[] GetSubKeyNames(); + /// + /// An array of strings that contains the names of the sub-keys for the current key. + /// + string[] GetSubKeyNames(); - /// - /// Retrieves the value associated with the specified name. - /// - /// The name of the value to retrieve. This string is not case-sensitive. - /// - /// The value associated with , or if is not found. - /// - string? GetValue(string name); - } + /// + /// Retrieves the value associated with the specified name. + /// + /// The name of the value to retrieve. This string is not case-sensitive. + /// + /// The value associated with , or if is not found. + /// + string? GetValue(string name); } diff --git a/src/SqlLocalDb/Interop/LocalDbInstanceApi.cs b/src/SqlLocalDb/Interop/LocalDbInstanceApi.cs index 099b6aba..2610923b 100644 --- a/src/SqlLocalDb/Interop/LocalDbInstanceApi.cs +++ b/src/SqlLocalDb/Interop/LocalDbInstanceApi.cs @@ -6,189 +6,716 @@ using System.Text; using Microsoft.Extensions.Logging; -namespace MartinCostello.SqlLocalDb.Interop +namespace MartinCostello.SqlLocalDb.Interop; + +/// +/// A class containing methods for interop with the SQL LocalDB Instance API. This class cannot be inherited. +/// +internal sealed class LocalDbInstanceApi : IDisposable { /// - /// A class containing methods for interop with the SQL LocalDB Instance API. This class cannot be inherited. + /// The maximum size of SQL Server LocalDB connection string. + /// + internal const int MaximumSqlConnectionStringBufferLength = 260; + + /// + /// The maximum size of SQL Server LocalDB instance names. + /// + internal const int MaximumInstanceNameLength = 128; + + /// + /// The maximum size of a SQL Server LocalDB version string. + /// + internal const int MaximumInstanceVersionLength = 43; + + /// + /// The maximum length of a SID string. + /// + internal const int MaximumSidStringLength = 186; + + /// + /// Specifies that error messages that are too long should be truncated. + /// + private const int LocalDbTruncateErrorMessage = 1; + + /// + /// An array containing the null character. This field is read-only. + /// + private static readonly char[] _nullArray = new char[] { '\0' }; + + /// + /// Synchronization object to protect loading the native library and its functions. This field is read-only. + /// + private readonly object _syncRoot = new object(); + + /// + /// Whether the instance has been disposed of. + /// + private bool _disposed; + + /// + /// The path of the library that was loaded. + /// + private string? _libraryPath; + + /// + /// The handle to the native SQL LocalDB API. + /// + private SafeLibraryHandle? _handle; + + /// + /// The delegate to the LocalDBCreateInstance LocalDB API function. + /// + private Functions.LocalDBCreateInstance? _localDBCreateInstance; + + /// + /// The delegate to the LocalDBDeleteInstance LocalDB API function. + /// + private Functions.LocalDBDeleteInstance? _localDBDeleteInstance; + + /// + /// The delegate to the LocalDBFormatMessage LocalDB API function. + /// + private Functions.LocalDBFormatMessage? _localDBFormatMessage; + + /// + /// The delegate to the LocalDBGetInstanceInfo LocalDB API function. + /// + private Functions.LocalDBGetInstanceInfo? _localDBGetInstanceInfo; + + /// + /// The delegate to the LocalDBGetInstances LocalDB API function. + /// + private Functions.LocalDBGetInstances? _localDBGetInstances; + + /// + /// The delegate to the LocalDBGetVersionInfo LocalDB API function. + /// + private Functions.LocalDBGetVersionInfo? _localDBGetVersionInfo; + + /// + /// The delegate to the LocalDBGetVersions LocalDB API function. + /// + private Functions.LocalDBGetVersions? _localDBGetVersions; + + /// + /// The delegate to the LocalDBShareInstance LocalDB API function. + /// + private Functions.LocalDBShareInstance? _localDBShareInstance; + + /// + /// The delegate to the LocalDBStartInstance LocalDB API function. + /// + private Functions.LocalDBStartInstance? _localDBStartInstance; + + /// + /// The delegate to the LocalDBStartTracing LocalDB API function. + /// + private Functions.LocalDBStartTracing? _localDBStartTracing; + + /// + /// The delegate to the LocalDBStopInstance LocalDB API function. + /// + private Functions.LocalDBStopInstance? _localDBStopInstance; + + /// + /// The delegate to the LocalDBStopTracing LocalDB API function. + /// + private Functions.LocalDBStopTracing? _localDBStopTracing; + + /// + /// The delegate to the LocalDBUnshareInstance LocalDB API function. + /// + private Functions.LocalDBUnshareInstance? _localDBUnshareInstance; + + /// + /// Initializes a new instance of the class. /// - internal sealed class LocalDbInstanceApi : IDisposable + /// The version of the SQL LocalDB Instance API to load. + /// The to use. + /// The logger to use. + internal LocalDbInstanceApi(string apiVersion, IRegistry registry, ILogger logger) { - /// - /// The maximum size of SQL Server LocalDB connection string. - /// - internal const int MaximumSqlConnectionStringBufferLength = 260; + ApiVersion = apiVersion; + Registry = registry; + Logger = logger; + } - /// - /// The maximum size of SQL Server LocalDB instance names. - /// - internal const int MaximumInstanceNameLength = 128; + /// + /// Finalizes an instance of the class. + /// + ~LocalDbInstanceApi() + { + Dispose(false); + } - /// - /// The maximum size of a SQL Server LocalDB version string. - /// - internal const int MaximumInstanceVersionLength = 43; + /// + /// Gets the version of the SQL LocalDB native API loaded, if any. + /// + internal Version? NativeApiVersion { get; private set; } - /// - /// The maximum length of a SID string. - /// - internal const int MaximumSidStringLength = 186; + /// + /// Gets the API version to use. + /// + private string ApiVersion { get; } - /// - /// Specifies that error messages that are too long should be truncated. - /// - private const int LocalDbTruncateErrorMessage = 1; + /// + /// Gets the to use. + /// + private ILogger Logger { get; } - /// - /// An array containing the null character. This field is read-only. - /// - private static readonly char[] _nullArray = new char[] { '\0' }; + /// + /// Gets the to use. + /// + private IRegistry Registry { get; } - /// - /// Synchronization object to protect loading the native library and its functions. This field is read-only. - /// - private readonly object _syncRoot = new object(); + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } - /// - /// Whether the instance has been disposed of. - /// - private bool _disposed; + /// + /// Marshals the specified of to a . + /// + /// The array to marshal as a . + /// + /// A representation of . + /// + internal static string MarshalString(byte[] bytes) + { + Debug.Assert(bytes != null, "bytes cannot be null."); + return Encoding.Unicode.GetString(bytes).TrimEnd(_nullArray); + } - /// - /// The path of the library that was loaded. - /// - private string? _libraryPath; + /// + /// Creates a new instance of SQL Server LocalDB. + /// + /// The LocalDB version, for example 11.0 or 11.0.1094.2. + /// The name for the LocalDB instance to create. + /// Reserved for future use. Currently should be set to 0. + /// The HRESULT returned by the LocalDB API. + internal int CreateInstance(string wszVersion, string pInstanceName, int dwFlags) + { + return EnsureFunctionAndInvoke( + "LocalDBCreateInstance", + ref _localDBCreateInstance, + (function) => function!(wszVersion, pInstanceName, dwFlags)); + } - /// - /// The handle to the native SQL LocalDB API. - /// - private SafeLibraryHandle? _handle; + /// + /// Deletes the specified SQL Server Express LocalDB instance. + /// + /// The name of the LocalDB instance to delete. + /// Reserved for future use. Currently should be set to 0. + /// The HRESULT returned by the LocalDB API. + internal int DeleteInstance(string pInstanceName, int dwFlags) + { + return EnsureFunctionAndInvoke( + "LocalDBDeleteInstance", + ref _localDBDeleteInstance, + (function) => function!(pInstanceName, dwFlags)); + } - /// - /// The delegate to the LocalDBCreateInstance LocalDB API function. - /// - private Functions.LocalDBCreateInstance? _localDBCreateInstance; + /// + /// Returns information for the specified SQL Server Express LocalDB instance, + /// such as whether it exists, the LocalDB version it uses, whether it is running, + /// and so on. + /// + /// The instance name. + /// The buffer to store the information about the LocalDB instance. + /// Holds the size of the InstanceInfo buffer. + /// The HRESULT returned by the LocalDB API. + internal int GetInstanceInfo(string wszInstanceName, IntPtr pInstanceInfo, int dwInstanceInfoSize) + { + return EnsureFunctionAndInvoke( + "LocalDBGetInstanceInfo", + ref _localDBGetInstanceInfo, + (function) => function!(wszInstanceName, pInstanceInfo, dwInstanceInfoSize)); + } - /// - /// The delegate to the LocalDBDeleteInstance LocalDB API function. - /// - private Functions.LocalDBDeleteInstance? _localDBDeleteInstance; + /// + /// Returns all SQL Server Express LocalDB instances with the given version. + /// + /// + /// When this function returns, contains the names of both named and default + /// LocalDB instances on the user’s workstation. + /// + /// + /// On input, contains the number of slots for instance names in the + /// buffer. On output, contains the number + /// of LocalDB instances found on the user’s workstation. + /// + /// The HRESULT returned by the LocalDB API. + internal int GetInstanceNames(IntPtr pInstanceNames, ref int lpdwNumberOfInstances) + { + var function = EnsureFunction("LocalDBGetInstances", ref _localDBGetInstances); - /// - /// The delegate to the LocalDBFormatMessage LocalDB API function. - /// - private Functions.LocalDBFormatMessage? _localDBFormatMessage; + if (function == null) + { + return SqlLocalDbErrors.NotInstalled; + } - /// - /// The delegate to the LocalDBGetInstanceInfo LocalDB API function. - /// - private Functions.LocalDBGetInstanceInfo? _localDBGetInstanceInfo; + return function(pInstanceNames, ref lpdwNumberOfInstances); + } + + /// + /// Returns the localized textual description for the specified SQL Server Express LocalDB error. + /// + /// The LocalDB error code. + /// The language desired (LANGID) or 0, in which case the Win32 FormatMessage language order is used. + /// The buffer to store the LocalDB error message. + /// + /// On input contains the size of the buffer in characters. On output, + /// if the given buffer size is too small, contains the buffer size required in characters, including + /// any trailing nulls. If the function succeeds, contains the number of characters in the message, + /// excluding any trailing nulls. + /// + /// The HRESULT returned by the LocalDB API. + internal int GetLocalDbError(int hrLocalDB, int dwLanguageId, StringBuilder wszMessage, ref int lpcchMessage) + { + var function = EnsureFunction("LocalDBFormatMessage", ref _localDBFormatMessage); + + if (function == null) + { + return SqlLocalDbErrors.NotInstalled; + } + + return function(hrLocalDB, LocalDbTruncateErrorMessage, dwLanguageId, wszMessage, ref lpcchMessage); + } + + /// + /// Returns information for the specified SQL Server Express LocalDB version, + /// such as whether it exists and the full LocalDB version number (including + /// build and release numbers). + /// + /// The LocalDB version name. + /// The buffer to store the information about the LocalDB version. + /// Holds the size of the VersionInfo buffer. + /// The HRESULT returned by the LocalDB API. + internal int GetVersionInfo(string wszVersionName, IntPtr pVersionInfo, int dwVersionInfoSize) + { + return EnsureFunctionAndInvoke( + "LocalDBGetVersionInfo", + ref _localDBGetVersionInfo, + (function) => function!(wszVersionName, pVersionInfo, dwVersionInfoSize)); + } + + /// + /// Returns all SQL Server Express LocalDB versions available on the computer. + /// + /// Contains names of the LocalDB versions that are available on the user’s workstation. + /// + /// On input holds the number of slots for versions in the + /// buffer. On output, holds the number of existing LocalDB versions. + /// + /// The HRESULT returned by the LocalDB API. + internal int GetVersions(IntPtr pVersion, ref int lpdwNumberOfVersions) + { + var function = EnsureFunction("LocalDBGetVersions", ref _localDBGetVersions); + + if (function == null) + { + return SqlLocalDbErrors.NotInstalled; + } + + return function(pVersion, ref lpdwNumberOfVersions); + } + + /// + /// Shares the specified SQL Server Express LocalDB instance with other + /// users of the computer, using the specified shared name. + /// + /// The SID of the instance owner. + /// The private name for the LocalDB instance to share. + /// The shared name for the LocalDB instance to share. + /// Reserved for future use. Currently should be set to 0. + /// The HRESULT returned by the LocalDB API. + internal int ShareInstance(IntPtr pOwnerSID, string pInstancePrivateName, string pInstanceSharedName, int dwFlags) + { + return EnsureFunctionAndInvoke( + "LocalDBShareInstance", + ref _localDBShareInstance, + (function) => function!(pOwnerSID, pInstancePrivateName, pInstanceSharedName, dwFlags)); + } + + /// + /// Starts the specified SQL Server Express LocalDB instance. + /// + /// The name of the LocalDB instance to start. + /// Reserved for future use. Currently should be set to 0. + /// The buffer to store the connection string to the LocalDB instance. + /// + /// On input contains the size of the buffer in + /// characters, including any trailing nulls. On output, if the given buffer size is + /// too small, contains the required buffer size in characters, including any trailing nulls. + /// + /// The HRESULT returned by the LocalDB API. + internal int StartInstance(string pInstanceName, int dwFlags, StringBuilder wszSqlConnection, ref int lpcchSqlConnection) + { + var function = EnsureFunction("LocalDBStartInstance", ref _localDBStartInstance); + + if (function == null) + { + return SqlLocalDbErrors.NotInstalled; + } + + return function(pInstanceName, dwFlags, wszSqlConnection, ref lpcchSqlConnection); + } + + /// + /// Enables tracing of API calls for all the SQL Server Express + /// LocalDB instances owned by the current Windows user. + /// + /// The HRESULT returned by the LocalDB API. + internal int StartTracing() + { + return EnsureFunctionAndInvoke( + "LocalDBStartTracing", + ref _localDBStartTracing, + (function) => function!()); + } + + /// + /// Stops the specified SQL Server Express LocalDB instance from running. + /// + /// The name of the LocalDB instance to stop. + /// One or a combination of the flag values specifying the way to stop the instance. + /// + /// The time in seconds to wait for this operation to complete. If this + /// value is 0, this function will return immediately without waiting for the LocalDB instance to stop. + /// + /// The HRESULT returned by the LocalDB API. + internal int StopInstance(string pInstanceName, StopInstanceOptions options, int ulTimeout) + { + return EnsureFunctionAndInvoke( + "LocalDBStopInstance", + ref _localDBStopInstance, + (function) => function!(pInstanceName, (int)options, ulTimeout)); + } + + /// + /// Disables tracing of API calls for all the SQL Server Express LocalDB + /// instances owned by the current Windows user. + /// + /// The HRESULT returned by the LocalDB API. + internal int StopTracing() + { + return EnsureFunctionAndInvoke( + "LocalDBStopTracing", + ref _localDBStopTracing, + (function) => function!()); + } + + /// + /// Stops the sharing of the specified SQL Server Express LocalDB instance. + /// + /// + /// The private name for the LocalDB instance to share. + /// + /// + /// Reserved for future use. Currently should be set to 0. + /// + /// The HRESULT returned by the LocalDB API. + internal int UnshareInstance(string pInstanceName, int dwFlags) + { + return EnsureFunctionAndInvoke( + "LocalDBUnshareInstance", + ref _localDBUnshareInstance, + (function) => function!(pInstanceName, dwFlags)); + } + + /// + /// Tries to obtaining the path to the latest version of the SQL LocalDB + /// native API DLL for the currently executing process. + /// + /// + /// When the method returns, contains the path to the SQL Local DB API + /// to use, if found; otherwise . + /// + /// + /// if the native API path was successfully found; + /// otherwise . + /// + internal bool TryGetLocalDbApiPath(out string? fileName) + { + fileName = null; + + string keyName = DeriveLocalDbRegistryKey(); + IRegistryKey? key = Registry.OpenSubKey(keyName); + + if (key == null) + { + Logger.RegistryKeyNotFound(keyName); + return false; + } + + Version? latestVersion = null; + Version? overrideVersion = null; + string? path = null; + + try + { + // Is there a setting overriding the version to load? + string overrideVersionString = ApiVersion; + + foreach (string versionString in key.GetSubKeyNames()) + { + if (!Version.TryParse(versionString, out Version? version)) + { + Logger.InvalidRegistryKey(versionString); + continue; + } + + if (!string.IsNullOrEmpty(overrideVersionString) && + overrideVersion == null && + string.Equals(versionString, overrideVersionString, StringComparison.OrdinalIgnoreCase)) + { + Logger.NativeApiVersionOverriddenByUser(version); + overrideVersion = version; + } + + if (latestVersion == null || + latestVersion < version) + { + latestVersion = version; + } + } + + if (!string.IsNullOrEmpty(overrideVersionString) && overrideVersion == null) + { + Logger.NativeApiVersionOverrideNotFound(overrideVersionString); + } + + Version? versionToUse = overrideVersion ?? latestVersion; + + if (versionToUse != null) + { + using (IRegistryKey? subkey = key.OpenSubKey(versionToUse.ToString())) + { + path = subkey?.GetValue("InstanceAPIPath"); + } + + NativeApiVersion = versionToUse; + } + } + finally + { + key.Dispose(); + } + + if (string.IsNullOrEmpty(path)) + { + Logger.NativeApiNotFound(); + return false; + } + + if (!File.Exists(path)) + { + Logger.NativeApiLibraryNotFound(path!); + return false; + } + + fileName = Path.GetFullPath(path); + return true; + } + + /// + /// Derives the name of the Windows registry key name to use to locate the SQL LocalDB Instance API. + /// + /// + /// The registry key name to use for the current process. + /// + private static string DeriveLocalDbRegistryKey() + { + // Open the appropriate Registry key if running as a 32-bit process on a 64-bit machine + bool isWow64Process = Environment.Is64BitOperatingSystem && !Environment.Is64BitProcess; + + return string.Format( + CultureInfo.InvariantCulture, + @"SOFTWARE\{0}Microsoft\Microsoft SQL Server Local DB\Installed Versions", + isWow64Process ? @"Wow6432Node\" : string.Empty); + } + + /// + /// Ensures that the specified delegate to an unmanaged function is initialized. + /// + /// The type of the delegate representing the unmanaged function. + /// The name of the unmanaged function to ensure is loaded. + /// A reference to a location to ensure contains a delegate for the specified function name. + /// + /// An instance of that points to the specified unmanaged + /// function, if found; otherwise . + /// + private T? EnsureFunction(string functionName, ref T? function) + where T : class, Delegate? + { + Debug.Assert(functionName != null, "functionName cannot be null."); + + if (function == null) + { + lock (_syncRoot) + { +#pragma warning disable CA1508 + if (function == null) +#pragma warning restore CA1508 + { + function = GetDelegate(functionName!); + } + } + } + + return function; + } + + /// + /// Ensures that the specified delegate to an unmanaged function is initialized and invokes the specified callback delegate if it does. + /// + /// The type of the delegate representing the unmanaged function. + /// The name of the unmanaged function to ensure is loaded. + /// A reference to a location to ensure contains a delegate for the specified function name. + /// A delegate to a callback method to invoke with the function if initialized. + /// + /// The result of invoking , if the function was + /// initialized; otherwise the value of is returned. + /// + private int EnsureFunctionAndInvoke(string functionName, ref T? function, Func callback) + where T : class, Delegate? + { + Debug.Assert(callback != null, "callback cannot be null."); + + function = EnsureFunction(functionName, ref function); + + return function == null ? SqlLocalDbErrors.NotInstalled : callback!(function); + } + + /// + /// Ensures that the LocalDB native API has been loaded. + /// + /// + /// A pointing to the loaded + /// SQL LocalDB API, if successful; otherwise . + /// + private SafeLibraryHandle? EnsureLocalDBLoaded() + { + if (_handle == null) + { + lock (_syncRoot) + { + if (_handle == null) + { + if (!TryGetLocalDbApiPath(out string? fileName) || fileName == null) + { + return null; + } - /// - /// The delegate to the LocalDBGetInstances LocalDB API function. - /// - private Functions.LocalDBGetInstances? _localDBGetInstances; + int dwFlags = 0; - /// - /// The delegate to the LocalDBGetVersionInfo LocalDB API function. - /// - private Functions.LocalDBGetVersionInfo? _localDBGetVersionInfo; + // Check if the local machine has KB2533623 installed in order + // to use the more secure flags when calling LoadLibraryEx + bool hasKB2533623; - /// - /// The delegate to the LocalDBGetVersions LocalDB API function. - /// - private Functions.LocalDBGetVersions? _localDBGetVersions; + using (var hModule = NativeMethods.LoadLibraryEx(NativeMethods.KernelLibName, IntPtr.Zero, 0)) + { + // If the AddDllDirectory function is found then the flags are supported + hasKB2533623 = NativeMethods.GetProcAddress(hModule, "AddDllDirectory") != IntPtr.Zero; + } - /// - /// The delegate to the LocalDBShareInstance LocalDB API function. - /// - private Functions.LocalDBShareInstance? _localDBShareInstance; + if (hasKB2533623) + { + // If KB2533623 is installed then specify the more secure LOAD_LIBRARY_SEARCH_DEFAULT_DIRS in dwFlags + dwFlags = NativeMethods.LOAD_LIBRARY_SEARCH_DEFAULT_DIRS; + } - /// - /// The delegate to the LocalDBStartInstance LocalDB API function. - /// - private Functions.LocalDBStartInstance? _localDBStartInstance; + _handle = NativeMethods.LoadLibraryEx(fileName, IntPtr.Zero, dwFlags); - /// - /// The delegate to the LocalDBStartTracing LocalDB API function. - /// - private Functions.LocalDBStartTracing? _localDBStartTracing; + if (_handle == null || _handle.IsInvalid) + { + int error = Marshal.GetLastWin32Error(); + Logger.NativeApiLoadFailed(fileName, error); + _handle = null; + } + else + { + Logger.NativeApiLoaded(fileName); + _libraryPath = fileName; + } + } + } + } - /// - /// The delegate to the LocalDBStopInstance LocalDB API function. - /// - private Functions.LocalDBStopInstance? _localDBStopInstance; + return _handle; + } - /// - /// The delegate to the LocalDBStopTracing LocalDB API function. - /// - private Functions.LocalDBStopTracing? _localDBStopTracing; + /// + /// Returns a delegate of the specified type to the specified unmanaged function. + /// + /// The type of the delegate to return. + /// The name of the unmanaged function. + /// + /// An instance of that points to the specified unmanaged + /// function, if found; otherwise . + /// + private T? GetDelegate(string functionName) + where T : class, Delegate? + { + Debug.Assert(functionName != null, "functionName cannot be null."); - /// - /// The delegate to the LocalDBUnshareInstance LocalDB API function. - /// - private Functions.LocalDBUnshareInstance? _localDBUnshareInstance; + SafeLibraryHandle? handle = EnsureLocalDBLoaded(); - /// - /// Initializes a new instance of the class. - /// - /// The version of the SQL LocalDB Instance API to load. - /// The to use. - /// The logger to use. - internal LocalDbInstanceApi(string apiVersion, IRegistry registry, ILogger logger) + if (handle == null) { - ApiVersion = apiVersion; - Registry = registry; - Logger = logger; + Logger.NativeApiNotLoaded(); + return null; } - /// - /// Finalizes an instance of the class. - /// - ~LocalDbInstanceApi() + IntPtr ptr = NativeMethods.GetProcAddress(handle, functionName!); + + if (ptr == IntPtr.Zero) { - Dispose(false); + Logger.NativeApiFunctionNotFound(functionName!); + return null; } - /// - /// Gets the version of the SQL LocalDB native API loaded, if any. - /// - internal Version? NativeApiVersion { get; private set; } + return Marshal.GetDelegateForFunctionPointer(ptr); + } - /// - /// Gets the API version to use. - /// - private string ApiVersion { get; } + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + /// + /// to release both managed and unmanaged resources; + /// to release only unmanaged resources. + /// + private void Dispose(bool disposing) + { + if (!_disposed) + { + if (disposing) + { + // Dispose of managed resources + } - /// - /// Gets the to use. - /// - private ILogger Logger { get; } + // Dispose of unmanaged resources + if (_handle != null) + { + _handle.Dispose(); - /// - /// Gets the to use. - /// - private IRegistry Registry { get; } + Logger.NativeApiUnloaded(_libraryPath!); - /// - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } + _libraryPath = null; + } - /// - /// Marshals the specified of to a . - /// - /// The array to marshal as a . - /// - /// A representation of . - /// - internal static string MarshalString(byte[] bytes) - { - Debug.Assert(bytes != null, "bytes cannot be null."); - return Encoding.Unicode.GetString(bytes).TrimEnd(_nullArray); + _disposed = true; } + } + /// + /// A class containing delegates to functions in the SQL LocalDB native API. + /// + private static class Functions + { /// /// Creates a new instance of SQL Server LocalDB. /// @@ -196,13 +723,14 @@ internal static string MarshalString(byte[] bytes) /// The name for the LocalDB instance to create. /// Reserved for future use. Currently should be set to 0. /// The HRESULT returned by the LocalDB API. - internal int CreateInstance(string wszVersion, string pInstanceName, int dwFlags) - { - return EnsureFunctionAndInvoke( - "LocalDBCreateInstance", - ref _localDBCreateInstance, - (function) => function!(wszVersion, pInstanceName, dwFlags)); - } + /// + /// See http://technet.microsoft.com/en-us/library/hh214784.aspx. + /// + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate int LocalDBCreateInstance( + [MarshalAs(UnmanagedType.LPWStr)] string wszVersion, + [MarshalAs(UnmanagedType.LPWStr)] string pInstanceName, + int dwFlags); /// /// Deletes the specified SQL Server Express LocalDB instance. @@ -210,13 +738,38 @@ internal int CreateInstance(string wszVersion, string pInstanceName, int dwFlags /// The name of the LocalDB instance to delete. /// Reserved for future use. Currently should be set to 0. /// The HRESULT returned by the LocalDB API. - internal int DeleteInstance(string pInstanceName, int dwFlags) - { - return EnsureFunctionAndInvoke( - "LocalDBDeleteInstance", - ref _localDBDeleteInstance, - (function) => function!(pInstanceName, dwFlags)); - } + /// + /// See http://technet.microsoft.com/en-us/library/hh214724.aspx. + /// + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate int LocalDBDeleteInstance( + [MarshalAs(UnmanagedType.LPWStr)] string pInstanceName, + int dwFlags); + + /// + /// Returns the localized textual description for the specified SQL Server Express LocalDB error. + /// + /// The LocalDB error code. + /// The flags specifying the behavior of this function. + /// The language desired (LANGID) or 0, in which case the Win32 FormatMessage language order is used. + /// The buffer to store the LocalDB error message. + /// + /// On input contains the size of the buffer in characters. On output, + /// if the given buffer size is too small, contains the buffer size required in characters, including + /// any trailing nulls. If the function succeeds, contains the number of characters in the message, + /// excluding any trailing nulls. + /// + /// The HRESULT returned by the LocalDB API. + /// + /// See http://technet.microsoft.com/en-us/library/hh214483.aspx. + /// + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate int LocalDBFormatMessage( + int hrLocalDB, + int dwFlags, + int dwLanguageId, + [MarshalAs(UnmanagedType.LPWStr)][Out] StringBuilder wszMessage, + ref int lpcchMessage); /// /// Returns information for the specified SQL Server Express LocalDB instance, @@ -227,13 +780,14 @@ internal int DeleteInstance(string pInstanceName, int dwFlags) /// The buffer to store the information about the LocalDB instance. /// Holds the size of the InstanceInfo buffer. /// The HRESULT returned by the LocalDB API. - internal int GetInstanceInfo(string wszInstanceName, IntPtr pInstanceInfo, int dwInstanceInfoSize) - { - return EnsureFunctionAndInvoke( - "LocalDBGetInstanceInfo", - ref _localDBGetInstanceInfo, - (function) => function!(wszInstanceName, pInstanceInfo, dwInstanceInfoSize)); - } + /// + /// See http://technet.microsoft.com/en-us/library/hh245734.aspx. + /// + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate int LocalDBGetInstanceInfo( + [MarshalAs(UnmanagedType.LPWStr)] string wszInstanceName, + IntPtr pInstanceInfo, + int dwInstanceInfoSize); /// /// Returns all SQL Server Express LocalDB instances with the given version. @@ -248,42 +802,11 @@ internal int GetInstanceInfo(string wszInstanceName, IntPtr pInstanceInfo, int d /// of LocalDB instances found on the user’s workstation. /// /// The HRESULT returned by the LocalDB API. - internal int GetInstanceNames(IntPtr pInstanceNames, ref int lpdwNumberOfInstances) - { - var function = EnsureFunction("LocalDBGetInstances", ref _localDBGetInstances); - - if (function == null) - { - return SqlLocalDbErrors.NotInstalled; - } - - return function(pInstanceNames, ref lpdwNumberOfInstances); - } - - /// - /// Returns the localized textual description for the specified SQL Server Express LocalDB error. - /// - /// The LocalDB error code. - /// The language desired (LANGID) or 0, in which case the Win32 FormatMessage language order is used. - /// The buffer to store the LocalDB error message. - /// - /// On input contains the size of the buffer in characters. On output, - /// if the given buffer size is too small, contains the buffer size required in characters, including - /// any trailing nulls. If the function succeeds, contains the number of characters in the message, - /// excluding any trailing nulls. - /// - /// The HRESULT returned by the LocalDB API. - internal int GetLocalDbError(int hrLocalDB, int dwLanguageId, StringBuilder wszMessage, ref int lpcchMessage) - { - var function = EnsureFunction("LocalDBFormatMessage", ref _localDBFormatMessage); - - if (function == null) - { - return SqlLocalDbErrors.NotInstalled; - } - - return function(hrLocalDB, LocalDbTruncateErrorMessage, dwLanguageId, wszMessage, ref lpcchMessage); - } + /// + /// See http://technet.microsoft.com/en-us/library/hh234622.aspx. + /// + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate int LocalDBGetInstances(IntPtr pInstanceNames, ref int lpdwNumberOfInstances); /// /// Returns information for the specified SQL Server Express LocalDB version, @@ -294,13 +817,14 @@ internal int GetLocalDbError(int hrLocalDB, int dwLanguageId, StringBuilder wszM /// The buffer to store the information about the LocalDB version. /// Holds the size of the VersionInfo buffer. /// The HRESULT returned by the LocalDB API. - internal int GetVersionInfo(string wszVersionName, IntPtr pVersionInfo, int dwVersionInfoSize) - { - return EnsureFunctionAndInvoke( - "LocalDBGetVersionInfo", - ref _localDBGetVersionInfo, - (function) => function!(wszVersionName, pVersionInfo, dwVersionInfoSize)); - } + /// + /// See http://technet.microsoft.com/en-us/library/hh234365.aspx. + /// + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate int LocalDBGetVersionInfo( + [MarshalAs(UnmanagedType.LPWStr)] string wszVersionName, + IntPtr pVersionInfo, + int dwVersionInfoSize); /// /// Returns all SQL Server Express LocalDB versions available on the computer. @@ -311,17 +835,11 @@ internal int GetVersionInfo(string wszVersionName, IntPtr pVersionInfo, int dwVe /// buffer. On output, holds the number of existing LocalDB versions. /// /// The HRESULT returned by the LocalDB API. - internal int GetVersions(IntPtr pVersion, ref int lpdwNumberOfVersions) - { - var function = EnsureFunction("LocalDBGetVersions", ref _localDBGetVersions); - - if (function == null) - { - return SqlLocalDbErrors.NotInstalled; - } - - return function(pVersion, ref lpdwNumberOfVersions); - } + /// + /// See http://technet.microsoft.com/en-us/library/hh231031.aspx. + /// + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate int LocalDBGetVersions(IntPtr pVersion, ref int lpdwNumberOfVersions); /// /// Shares the specified SQL Server Express LocalDB instance with other @@ -332,13 +850,15 @@ internal int GetVersions(IntPtr pVersion, ref int lpdwNumberOfVersions) /// The shared name for the LocalDB instance to share. /// Reserved for future use. Currently should be set to 0. /// The HRESULT returned by the LocalDB API. - internal int ShareInstance(IntPtr pOwnerSID, string pInstancePrivateName, string pInstanceSharedName, int dwFlags) - { - return EnsureFunctionAndInvoke( - "LocalDBShareInstance", - ref _localDBShareInstance, - (function) => function!(pOwnerSID, pInstancePrivateName, pInstanceSharedName, dwFlags)); - } + /// + /// See http://technet.microsoft.com/en-us/library/hh245693.aspx. + /// + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate int LocalDBShareInstance( + IntPtr pOwnerSID, + [MarshalAs(UnmanagedType.LPWStr)] string pInstancePrivateName, + [MarshalAs(UnmanagedType.LPWStr)] string pInstanceSharedName, + int dwFlags); /// /// Starts the specified SQL Server Express LocalDB instance. @@ -352,589 +872,68 @@ internal int ShareInstance(IntPtr pOwnerSID, string pInstancePrivateName, string /// too small, contains the required buffer size in characters, including any trailing nulls. /// /// The HRESULT returned by the LocalDB API. - internal int StartInstance(string pInstanceName, int dwFlags, StringBuilder wszSqlConnection, ref int lpcchSqlConnection) - { - var function = EnsureFunction("LocalDBStartInstance", ref _localDBStartInstance); - - if (function == null) - { - return SqlLocalDbErrors.NotInstalled; - } - - return function(pInstanceName, dwFlags, wszSqlConnection, ref lpcchSqlConnection); - } + /// + /// See http://technet.microsoft.com/en-us/library/hh217143.aspx. + /// + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate int LocalDBStartInstance( + [MarshalAs(UnmanagedType.LPWStr)] string pInstanceName, + int dwFlags, + [MarshalAs(UnmanagedType.LPWStr)][Out] StringBuilder wszSqlConnection, + ref int lpcchSqlConnection); /// /// Enables tracing of API calls for all the SQL Server Express /// LocalDB instances owned by the current Windows user. /// /// The HRESULT returned by the LocalDB API. - internal int StartTracing() - { - return EnsureFunctionAndInvoke( - "LocalDBStartTracing", - ref _localDBStartTracing, - (function) => function!()); - } + /// + /// See http://technet.microsoft.com/en-us/library/hh247594.aspx. + /// + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate int LocalDBStartTracing(); /// /// Stops the specified SQL Server Express LocalDB instance from running. /// /// The name of the LocalDB instance to stop. - /// One or a combination of the flag values specifying the way to stop the instance. + /// One or a combination of the flag values specifying the way to stop the instance. /// /// The time in seconds to wait for this operation to complete. If this /// value is 0, this function will return immediately without waiting for the LocalDB instance to stop. /// /// The HRESULT returned by the LocalDB API. - internal int StopInstance(string pInstanceName, StopInstanceOptions options, int ulTimeout) - { - return EnsureFunctionAndInvoke( - "LocalDBStopInstance", - ref _localDBStopInstance, - (function) => function!(pInstanceName, (int)options, ulTimeout)); - } + /// + /// See http://technet.microsoft.com/en-us/library/hh215035.aspx. + /// + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate int LocalDBStopInstance( + [MarshalAs(UnmanagedType.LPWStr)] string pInstanceName, + int dwFlags, + int ulTimeout); /// /// Disables tracing of API calls for all the SQL Server Express LocalDB /// instances owned by the current Windows user. /// /// The HRESULT returned by the LocalDB API. - internal int StopTracing() - { - return EnsureFunctionAndInvoke( - "LocalDBStopTracing", - ref _localDBStopTracing, - (function) => function!()); - } + /// + /// See http://technet.microsoft.com/en-us/library/hh214120.aspx. + /// + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate int LocalDBStopTracing(); /// /// Stops the sharing of the specified SQL Server Express LocalDB instance. /// - /// - /// The private name for the LocalDB instance to share. - /// - /// - /// Reserved for future use. Currently should be set to 0. - /// + /// The private name for the LocalDB instance to share. + /// Reserved for future use. Currently should be set to 0. /// The HRESULT returned by the LocalDB API. - internal int UnshareInstance(string pInstanceName, int dwFlags) - { - return EnsureFunctionAndInvoke( - "LocalDBUnshareInstance", - ref _localDBUnshareInstance, - (function) => function!(pInstanceName, dwFlags)); - } - - /// - /// Tries to obtaining the path to the latest version of the SQL LocalDB - /// native API DLL for the currently executing process. - /// - /// - /// When the method returns, contains the path to the SQL Local DB API - /// to use, if found; otherwise . - /// - /// - /// if the native API path was successfully found; - /// otherwise . - /// - internal bool TryGetLocalDbApiPath(out string? fileName) - { - fileName = null; - - string keyName = DeriveLocalDbRegistryKey(); - IRegistryKey? key = Registry.OpenSubKey(keyName); - - if (key == null) - { - Logger.RegistryKeyNotFound(keyName); - return false; - } - - Version? latestVersion = null; - Version? overrideVersion = null; - string? path = null; - - try - { - // Is there a setting overriding the version to load? - string overrideVersionString = ApiVersion; - - foreach (string versionString in key.GetSubKeyNames()) - { - if (!Version.TryParse(versionString, out Version? version)) - { - Logger.InvalidRegistryKey(versionString); - continue; - } - - if (!string.IsNullOrEmpty(overrideVersionString) && - overrideVersion == null && - string.Equals(versionString, overrideVersionString, StringComparison.OrdinalIgnoreCase)) - { - Logger.NativeApiVersionOverriddenByUser(version); - overrideVersion = version; - } - - if (latestVersion == null || - latestVersion < version) - { - latestVersion = version; - } - } - - if (!string.IsNullOrEmpty(overrideVersionString) && overrideVersion == null) - { - Logger.NativeApiVersionOverrideNotFound(overrideVersionString); - } - - Version? versionToUse = overrideVersion ?? latestVersion; - - if (versionToUse != null) - { - using (IRegistryKey? subkey = key.OpenSubKey(versionToUse.ToString())) - { - path = subkey?.GetValue("InstanceAPIPath"); - } - - NativeApiVersion = versionToUse; - } - } - finally - { - key.Dispose(); - } - - if (string.IsNullOrEmpty(path)) - { - Logger.NativeApiNotFound(); - return false; - } - - if (!File.Exists(path)) - { - Logger.NativeApiLibraryNotFound(path!); - return false; - } - - fileName = Path.GetFullPath(path); - return true; - } - - /// - /// Derives the name of the Windows registry key name to use to locate the SQL LocalDB Instance API. - /// - /// - /// The registry key name to use for the current process. - /// - private static string DeriveLocalDbRegistryKey() - { - // Open the appropriate Registry key if running as a 32-bit process on a 64-bit machine - bool isWow64Process = Environment.Is64BitOperatingSystem && !Environment.Is64BitProcess; - - return string.Format( - CultureInfo.InvariantCulture, - @"SOFTWARE\{0}Microsoft\Microsoft SQL Server Local DB\Installed Versions", - isWow64Process ? @"Wow6432Node\" : string.Empty); - } - - /// - /// Ensures that the specified delegate to an unmanaged function is initialized. - /// - /// The type of the delegate representing the unmanaged function. - /// The name of the unmanaged function to ensure is loaded. - /// A reference to a location to ensure contains a delegate for the specified function name. - /// - /// An instance of that points to the specified unmanaged - /// function, if found; otherwise . - /// - private T? EnsureFunction(string functionName, ref T? function) - where T : class, Delegate? - { - Debug.Assert(functionName != null, "functionName cannot be null."); - - if (function == null) - { - lock (_syncRoot) - { -#pragma warning disable CA1508 - if (function == null) -#pragma warning restore CA1508 - { - function = GetDelegate(functionName!); - } - } - } - - return function; - } - - /// - /// Ensures that the specified delegate to an unmanaged function is initialized and invokes the specified callback delegate if it does. - /// - /// The type of the delegate representing the unmanaged function. - /// The name of the unmanaged function to ensure is loaded. - /// A reference to a location to ensure contains a delegate for the specified function name. - /// A delegate to a callback method to invoke with the function if initialized. - /// - /// The result of invoking , if the function was - /// initialized; otherwise the value of is returned. - /// - private int EnsureFunctionAndInvoke(string functionName, ref T? function, Func callback) - where T : class, Delegate? - { - Debug.Assert(callback != null, "callback cannot be null."); - - function = EnsureFunction(functionName, ref function); - - return function == null ? SqlLocalDbErrors.NotInstalled : callback!(function); - } - - /// - /// Ensures that the LocalDB native API has been loaded. - /// - /// - /// A pointing to the loaded - /// SQL LocalDB API, if successful; otherwise . - /// - private SafeLibraryHandle? EnsureLocalDBLoaded() - { - if (_handle == null) - { - lock (_syncRoot) - { - if (_handle == null) - { - if (!TryGetLocalDbApiPath(out string? fileName) || fileName == null) - { - return null; - } - - int dwFlags = 0; - - // Check if the local machine has KB2533623 installed in order - // to use the more secure flags when calling LoadLibraryEx - bool hasKB2533623; - - using (var hModule = NativeMethods.LoadLibraryEx(NativeMethods.KernelLibName, IntPtr.Zero, 0)) - { - // If the AddDllDirectory function is found then the flags are supported - hasKB2533623 = NativeMethods.GetProcAddress(hModule, "AddDllDirectory") != IntPtr.Zero; - } - - if (hasKB2533623) - { - // If KB2533623 is installed then specify the more secure LOAD_LIBRARY_SEARCH_DEFAULT_DIRS in dwFlags - dwFlags = NativeMethods.LOAD_LIBRARY_SEARCH_DEFAULT_DIRS; - } - - _handle = NativeMethods.LoadLibraryEx(fileName, IntPtr.Zero, dwFlags); - - if (_handle == null || _handle.IsInvalid) - { - int error = Marshal.GetLastWin32Error(); - Logger.NativeApiLoadFailed(fileName, error); - _handle = null; - } - else - { - Logger.NativeApiLoaded(fileName); - _libraryPath = fileName; - } - } - } - } - - return _handle; - } - - /// - /// Returns a delegate of the specified type to the specified unmanaged function. - /// - /// The type of the delegate to return. - /// The name of the unmanaged function. - /// - /// An instance of that points to the specified unmanaged - /// function, if found; otherwise . - /// - private T? GetDelegate(string functionName) - where T : class, Delegate? - { - Debug.Assert(functionName != null, "functionName cannot be null."); - - SafeLibraryHandle? handle = EnsureLocalDBLoaded(); - - if (handle == null) - { - Logger.NativeApiNotLoaded(); - return null; - } - - IntPtr ptr = NativeMethods.GetProcAddress(handle, functionName!); - - if (ptr == IntPtr.Zero) - { - Logger.NativeApiFunctionNotFound(functionName!); - return null; - } - - return Marshal.GetDelegateForFunctionPointer(ptr); - } - - /// - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// - /// - /// to release both managed and unmanaged resources; - /// to release only unmanaged resources. - /// - private void Dispose(bool disposing) - { - if (!_disposed) - { - if (disposing) - { - // Dispose of managed resources - } - - // Dispose of unmanaged resources - if (_handle != null) - { - _handle.Dispose(); - - Logger.NativeApiUnloaded(_libraryPath!); - - _libraryPath = null; - } - - _disposed = true; - } - } - - /// - /// A class containing delegates to functions in the SQL LocalDB native API. - /// - private static class Functions - { - /// - /// Creates a new instance of SQL Server LocalDB. - /// - /// The LocalDB version, for example 11.0 or 11.0.1094.2. - /// The name for the LocalDB instance to create. - /// Reserved for future use. Currently should be set to 0. - /// The HRESULT returned by the LocalDB API. - /// - /// See http://technet.microsoft.com/en-us/library/hh214784.aspx. - /// - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - internal delegate int LocalDBCreateInstance( - [MarshalAs(UnmanagedType.LPWStr)] string wszVersion, - [MarshalAs(UnmanagedType.LPWStr)] string pInstanceName, - int dwFlags); - - /// - /// Deletes the specified SQL Server Express LocalDB instance. - /// - /// The name of the LocalDB instance to delete. - /// Reserved for future use. Currently should be set to 0. - /// The HRESULT returned by the LocalDB API. - /// - /// See http://technet.microsoft.com/en-us/library/hh214724.aspx. - /// - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - internal delegate int LocalDBDeleteInstance( - [MarshalAs(UnmanagedType.LPWStr)] string pInstanceName, - int dwFlags); - - /// - /// Returns the localized textual description for the specified SQL Server Express LocalDB error. - /// - /// The LocalDB error code. - /// The flags specifying the behavior of this function. - /// The language desired (LANGID) or 0, in which case the Win32 FormatMessage language order is used. - /// The buffer to store the LocalDB error message. - /// - /// On input contains the size of the buffer in characters. On output, - /// if the given buffer size is too small, contains the buffer size required in characters, including - /// any trailing nulls. If the function succeeds, contains the number of characters in the message, - /// excluding any trailing nulls. - /// - /// The HRESULT returned by the LocalDB API. - /// - /// See http://technet.microsoft.com/en-us/library/hh214483.aspx. - /// - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - internal delegate int LocalDBFormatMessage( - int hrLocalDB, - int dwFlags, - int dwLanguageId, - [MarshalAs(UnmanagedType.LPWStr)][Out] StringBuilder wszMessage, - ref int lpcchMessage); - - /// - /// Returns information for the specified SQL Server Express LocalDB instance, - /// such as whether it exists, the LocalDB version it uses, whether it is running, - /// and so on. - /// - /// The instance name. - /// The buffer to store the information about the LocalDB instance. - /// Holds the size of the InstanceInfo buffer. - /// The HRESULT returned by the LocalDB API. - /// - /// See http://technet.microsoft.com/en-us/library/hh245734.aspx. - /// - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - internal delegate int LocalDBGetInstanceInfo( - [MarshalAs(UnmanagedType.LPWStr)] string wszInstanceName, - IntPtr pInstanceInfo, - int dwInstanceInfoSize); - - /// - /// Returns all SQL Server Express LocalDB instances with the given version. - /// - /// - /// When this function returns, contains the names of both named and default - /// LocalDB instances on the user’s workstation. - /// - /// - /// On input, contains the number of slots for instance names in the - /// buffer. On output, contains the number - /// of LocalDB instances found on the user’s workstation. - /// - /// The HRESULT returned by the LocalDB API. - /// - /// See http://technet.microsoft.com/en-us/library/hh234622.aspx. - /// - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - internal delegate int LocalDBGetInstances(IntPtr pInstanceNames, ref int lpdwNumberOfInstances); - - /// - /// Returns information for the specified SQL Server Express LocalDB version, - /// such as whether it exists and the full LocalDB version number (including - /// build and release numbers). - /// - /// The LocalDB version name. - /// The buffer to store the information about the LocalDB version. - /// Holds the size of the VersionInfo buffer. - /// The HRESULT returned by the LocalDB API. - /// - /// See http://technet.microsoft.com/en-us/library/hh234365.aspx. - /// - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - internal delegate int LocalDBGetVersionInfo( - [MarshalAs(UnmanagedType.LPWStr)] string wszVersionName, - IntPtr pVersionInfo, - int dwVersionInfoSize); - - /// - /// Returns all SQL Server Express LocalDB versions available on the computer. - /// - /// Contains names of the LocalDB versions that are available on the user’s workstation. - /// - /// On input holds the number of slots for versions in the - /// buffer. On output, holds the number of existing LocalDB versions. - /// - /// The HRESULT returned by the LocalDB API. - /// - /// See http://technet.microsoft.com/en-us/library/hh231031.aspx. - /// - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - internal delegate int LocalDBGetVersions(IntPtr pVersion, ref int lpdwNumberOfVersions); - - /// - /// Shares the specified SQL Server Express LocalDB instance with other - /// users of the computer, using the specified shared name. - /// - /// The SID of the instance owner. - /// The private name for the LocalDB instance to share. - /// The shared name for the LocalDB instance to share. - /// Reserved for future use. Currently should be set to 0. - /// The HRESULT returned by the LocalDB API. - /// - /// See http://technet.microsoft.com/en-us/library/hh245693.aspx. - /// - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - internal delegate int LocalDBShareInstance( - IntPtr pOwnerSID, - [MarshalAs(UnmanagedType.LPWStr)] string pInstancePrivateName, - [MarshalAs(UnmanagedType.LPWStr)] string pInstanceSharedName, - int dwFlags); - - /// - /// Starts the specified SQL Server Express LocalDB instance. - /// - /// The name of the LocalDB instance to start. - /// Reserved for future use. Currently should be set to 0. - /// The buffer to store the connection string to the LocalDB instance. - /// - /// On input contains the size of the buffer in - /// characters, including any trailing nulls. On output, if the given buffer size is - /// too small, contains the required buffer size in characters, including any trailing nulls. - /// - /// The HRESULT returned by the LocalDB API. - /// - /// See http://technet.microsoft.com/en-us/library/hh217143.aspx. - /// - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - internal delegate int LocalDBStartInstance( - [MarshalAs(UnmanagedType.LPWStr)] string pInstanceName, - int dwFlags, - [MarshalAs(UnmanagedType.LPWStr)][Out] StringBuilder wszSqlConnection, - ref int lpcchSqlConnection); - - /// - /// Enables tracing of API calls for all the SQL Server Express - /// LocalDB instances owned by the current Windows user. - /// - /// The HRESULT returned by the LocalDB API. - /// - /// See http://technet.microsoft.com/en-us/library/hh247594.aspx. - /// - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - internal delegate int LocalDBStartTracing(); - - /// - /// Stops the specified SQL Server Express LocalDB instance from running. - /// - /// The name of the LocalDB instance to stop. - /// One or a combination of the flag values specifying the way to stop the instance. - /// - /// The time in seconds to wait for this operation to complete. If this - /// value is 0, this function will return immediately without waiting for the LocalDB instance to stop. - /// - /// The HRESULT returned by the LocalDB API. - /// - /// See http://technet.microsoft.com/en-us/library/hh215035.aspx. - /// - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - internal delegate int LocalDBStopInstance( - [MarshalAs(UnmanagedType.LPWStr)] string pInstanceName, - int dwFlags, - int ulTimeout); - - /// - /// Disables tracing of API calls for all the SQL Server Express LocalDB - /// instances owned by the current Windows user. - /// - /// The HRESULT returned by the LocalDB API. - /// - /// See http://technet.microsoft.com/en-us/library/hh214120.aspx. - /// - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - internal delegate int LocalDBStopTracing(); - - /// - /// Stops the sharing of the specified SQL Server Express LocalDB instance. - /// - /// The private name for the LocalDB instance to share. - /// Reserved for future use. Currently should be set to 0. - /// The HRESULT returned by the LocalDB API. - /// - /// See http://technet.microsoft.com/en-us/library/hh215383.aspx. - /// - internal delegate int LocalDBUnshareInstance( - [MarshalAs(UnmanagedType.LPWStr)] string pInstanceName, - int dwFlags); - } + /// + /// See http://technet.microsoft.com/en-us/library/hh215383.aspx. + /// + internal delegate int LocalDBUnshareInstance( + [MarshalAs(UnmanagedType.LPWStr)] string pInstanceName, + int dwFlags); } } diff --git a/src/SqlLocalDb/Interop/LocalDbInstanceInfo.cs b/src/SqlLocalDb/Interop/LocalDbInstanceInfo.cs index 15e17d92..affa0371 100644 --- a/src/SqlLocalDb/Interop/LocalDbInstanceInfo.cs +++ b/src/SqlLocalDb/Interop/LocalDbInstanceInfo.cs @@ -4,228 +4,227 @@ using System.Diagnostics; using System.Runtime.InteropServices; -namespace MartinCostello.SqlLocalDb.Interop +namespace MartinCostello.SqlLocalDb.Interop; + +/// +/// A structure representing information about a SQL Server LocalDB instance. +/// +/// +/// See http://msdn.microsoft.com/en-us/library/hh245734.aspx. +/// +[DebuggerDisplay("{DebuggerDisplayName}")] +[StructLayout(LayoutKind.Sequential)] +internal struct LocalDbInstanceInfo : ISqlLocalDbInstanceInfo { /// - /// A structure representing information about a SQL Server LocalDB instance. + /// The size of an unmanaged type in bytes. This field is read-only. + /// + internal static readonly int MarshalSize = Marshal.SizeOf(typeof(LocalDbInstanceInfo)); + + /// + /// Contains the size of the struct. + /// + /// + /// Maps to the cbLocalDBInstanceInfoSize member. + /// + internal uint Size; + + /// + /// The name of the LocalDB instance. + /// + /// + /// Maps to the wszInstanceName member. + /// + [MarshalAs( + UnmanagedType.ByValArray, + SizeConst = (LocalDbInstanceApi.MaximumInstanceNameLength + 1) * sizeof(char))] + internal byte[] InstanceName; + + /// + /// Whether the instance files exist on disk. + /// + /// + /// Maps to the bExists member. + /// + internal bool Exists; + + /// + /// Whether the Registry configuration is corrupt. + /// + /// + /// Maps to the bConfigurationCorrupted member. + /// + internal bool ConfigurationCorrupted; + + /// + /// Whether the instance is currently running. + /// + /// + /// Maps to the bIsRunning member. + /// + internal bool IsRunning; + + /// + /// The LocalDB major version number. /// /// - /// See http://msdn.microsoft.com/en-us/library/hh245734.aspx. + /// Maps to the dwMajor member. /// - [DebuggerDisplay("{DebuggerDisplayName}")] - [StructLayout(LayoutKind.Sequential)] - internal struct LocalDbInstanceInfo : ISqlLocalDbInstanceInfo + internal uint Major; + + /// + /// The LocalDB minor version number. + /// + /// + /// Maps to the dwMinor member. + /// + internal uint Minor; + + /// + /// The LocalDB build version number. + /// + /// + /// Maps to the dwBuild member. + /// + internal uint Build; + + /// + /// The LocalDB revision version number. + /// + /// + /// Maps to the dwRevision member. + /// + internal uint Revision; + + /// + /// The UTC date and time the instance was last started. + /// + /// + /// Maps to the ftLastStartUTC member. + /// + internal System.Runtime.InteropServices.ComTypes.FILETIME LastStartUtc; + + /// + /// The named pipe that should be used to communicate with the instance. + /// + /// + /// Maps to the wszConnection member. + /// + [MarshalAs( + UnmanagedType.ByValArray, + SizeConst = LocalDbInstanceApi.MaximumSqlConnectionStringBufferLength * sizeof(char))] + internal byte[] Connection; + + /// + /// Whether the instance is shared. + /// + /// + /// Maps to the bIsShared member. + /// + internal bool IsShared; + + /// + /// The shared name of the LocalDB instance if the instance is shared. + /// + /// + /// Maps to the wszSharedInstanceName member. + /// + [MarshalAs( + UnmanagedType.ByValArray, + SizeConst = (LocalDbInstanceApi.MaximumInstanceNameLength + 1) * sizeof(char))] + internal byte[] SharedInstanceName; + + /// + /// The SID of the LocalDB instance owner if the instance is shared. + /// + /// + /// Maps to the wszOwnerSID member. + /// + [MarshalAs( + UnmanagedType.ByValArray, + SizeConst = (LocalDbInstanceApi.MaximumSidStringLength + 1) * sizeof(char))] + internal byte[] OwnerSID; + + /// + /// Whether the instance is automatic. + /// + /// + /// Maps to the bIsAutomatic member. + /// + internal bool IsAutomatic; + + /// + /// Gets a value indicating whether the Registry configuration is corrupt. + /// + bool ISqlLocalDbInstanceInfo.ConfigurationCorrupt => ConfigurationCorrupted; + + /// + /// Gets a value indicating whether this is exists. + /// + bool ISqlLocalDbInstanceInfo.Exists => Exists; + + /// + /// Gets a value indicating whether the instance is automatic. + /// + bool ISqlLocalDbInstanceInfo.IsAutomatic => IsAutomatic; + + /// + /// Gets a value indicating whether the instance is currently running. + /// + bool ISqlLocalDbInstanceInfo.IsRunning => IsRunning; + + /// + /// Gets a value indicating whether the instance is shared. + /// + bool ISqlLocalDbInstanceInfo.IsShared => IsShared; + + /// + /// Gets the UTC date and time the instance was last started. + /// + DateTime ISqlLocalDbInstanceInfo.LastStartTimeUtc { - /// - /// The size of an unmanaged type in bytes. This field is read-only. - /// - internal static readonly int MarshalSize = Marshal.SizeOf(typeof(LocalDbInstanceInfo)); - - /// - /// Contains the size of the struct. - /// - /// - /// Maps to the cbLocalDBInstanceInfoSize member. - /// - internal uint Size; - - /// - /// The name of the LocalDB instance. - /// - /// - /// Maps to the wszInstanceName member. - /// - [MarshalAs( - UnmanagedType.ByValArray, - SizeConst = (LocalDbInstanceApi.MaximumInstanceNameLength + 1) * sizeof(char))] - internal byte[] InstanceName; - - /// - /// Whether the instance files exist on disk. - /// - /// - /// Maps to the bExists member. - /// - internal bool Exists; - - /// - /// Whether the Registry configuration is corrupt. - /// - /// - /// Maps to the bConfigurationCorrupted member. - /// - internal bool ConfigurationCorrupted; - - /// - /// Whether the instance is currently running. - /// - /// - /// Maps to the bIsRunning member. - /// - internal bool IsRunning; - - /// - /// The LocalDB major version number. - /// - /// - /// Maps to the dwMajor member. - /// - internal uint Major; - - /// - /// The LocalDB minor version number. - /// - /// - /// Maps to the dwMinor member. - /// - internal uint Minor; - - /// - /// The LocalDB build version number. - /// - /// - /// Maps to the dwBuild member. - /// - internal uint Build; - - /// - /// The LocalDB revision version number. - /// - /// - /// Maps to the dwRevision member. - /// - internal uint Revision; - - /// - /// The UTC date and time the instance was last started. - /// - /// - /// Maps to the ftLastStartUTC member. - /// - internal System.Runtime.InteropServices.ComTypes.FILETIME LastStartUtc; - - /// - /// The named pipe that should be used to communicate with the instance. - /// - /// - /// Maps to the wszConnection member. - /// - [MarshalAs( - UnmanagedType.ByValArray, - SizeConst = LocalDbInstanceApi.MaximumSqlConnectionStringBufferLength * sizeof(char))] - internal byte[] Connection; - - /// - /// Whether the instance is shared. - /// - /// - /// Maps to the bIsShared member. - /// - internal bool IsShared; - - /// - /// The shared name of the LocalDB instance if the instance is shared. - /// - /// - /// Maps to the wszSharedInstanceName member. - /// - [MarshalAs( - UnmanagedType.ByValArray, - SizeConst = (LocalDbInstanceApi.MaximumInstanceNameLength + 1) * sizeof(char))] - internal byte[] SharedInstanceName; - - /// - /// The SID of the LocalDB instance owner if the instance is shared. - /// - /// - /// Maps to the wszOwnerSID member. - /// - [MarshalAs( - UnmanagedType.ByValArray, - SizeConst = (LocalDbInstanceApi.MaximumSidStringLength + 1) * sizeof(char))] - internal byte[] OwnerSID; - - /// - /// Whether the instance is automatic. - /// - /// - /// Maps to the bIsAutomatic member. - /// - internal bool IsAutomatic; - - /// - /// Gets a value indicating whether the Registry configuration is corrupt. - /// - bool ISqlLocalDbInstanceInfo.ConfigurationCorrupt => ConfigurationCorrupted; - - /// - /// Gets a value indicating whether this is exists. - /// - bool ISqlLocalDbInstanceInfo.Exists => Exists; - - /// - /// Gets a value indicating whether the instance is automatic. - /// - bool ISqlLocalDbInstanceInfo.IsAutomatic => IsAutomatic; - - /// - /// Gets a value indicating whether the instance is currently running. - /// - bool ISqlLocalDbInstanceInfo.IsRunning => IsRunning; - - /// - /// Gets a value indicating whether the instance is shared. - /// - bool ISqlLocalDbInstanceInfo.IsShared => IsShared; - - /// - /// Gets the UTC date and time the instance was last started. - /// - DateTime ISqlLocalDbInstanceInfo.LastStartTimeUtc + get { - get + // Return DateTime.MinValue equivalent, rather than 01/01/1600 + if (LastStartUtc.dwHighDateTime == 0 && + LastStartUtc.dwLowDateTime == 0) { - // Return DateTime.MinValue equivalent, rather than 01/01/1600 - if (LastStartUtc.dwHighDateTime == 0 && - LastStartUtc.dwLowDateTime == 0) - { - return new DateTime(0, DateTimeKind.Utc); - } - - return DateTime.FromFileTimeUtc(((long)LastStartUtc.dwHighDateTime << 32) | (uint)LastStartUtc.dwLowDateTime); + return new DateTime(0, DateTimeKind.Utc); } - } - /// - /// Gets the LocalDB version for the instance. - /// - Version ISqlLocalDbInstanceInfo.LocalDbVersion => new Version((int)Major, (int)Minor, (int)Build, (int)Revision); - - /// - /// Gets the name of the instance. - /// - string ISqlLocalDbInstanceInfo.Name => LocalDbInstanceApi.MarshalString(InstanceName); - - /// - /// Gets the named pipe that should be used to communicate with the instance. - /// - string ISqlLocalDbInstanceInfo.NamedPipe => LocalDbInstanceApi.MarshalString(Connection); - - /// - /// Gets the SID of the LocalDB instance owner if the instance is shared. - /// - string ISqlLocalDbInstanceInfo.OwnerSid => LocalDbInstanceApi.MarshalString(OwnerSID); - - /// - /// Gets the shared name of the LocalDB instance if the instance is shared. - /// - string ISqlLocalDbInstanceInfo.SharedName => LocalDbInstanceApi.MarshalString(SharedInstanceName); - - /// - /// Gets the name to display in the debugger. - /// - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] - private string DebuggerDisplayName => ((ISqlLocalDbInstanceInfo)this).Name; + return DateTime.FromFileTimeUtc(((long)LastStartUtc.dwHighDateTime << 32) | (uint)LastStartUtc.dwLowDateTime); + } } + + /// + /// Gets the LocalDB version for the instance. + /// + Version ISqlLocalDbInstanceInfo.LocalDbVersion => new Version((int)Major, (int)Minor, (int)Build, (int)Revision); + + /// + /// Gets the name of the instance. + /// + string ISqlLocalDbInstanceInfo.Name => LocalDbInstanceApi.MarshalString(InstanceName); + + /// + /// Gets the named pipe that should be used to communicate with the instance. + /// + string ISqlLocalDbInstanceInfo.NamedPipe => LocalDbInstanceApi.MarshalString(Connection); + + /// + /// Gets the SID of the LocalDB instance owner if the instance is shared. + /// + string ISqlLocalDbInstanceInfo.OwnerSid => LocalDbInstanceApi.MarshalString(OwnerSID); + + /// + /// Gets the shared name of the LocalDB instance if the instance is shared. + /// + string ISqlLocalDbInstanceInfo.SharedName => LocalDbInstanceApi.MarshalString(SharedInstanceName); + + /// + /// Gets the name to display in the debugger. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + private string DebuggerDisplayName => ((ISqlLocalDbInstanceInfo)this).Name; } diff --git a/src/SqlLocalDb/Interop/LocalDbVersionInfo.cs b/src/SqlLocalDb/Interop/LocalDbVersionInfo.cs index 0cd4ea8c..904c6295 100644 --- a/src/SqlLocalDb/Interop/LocalDbVersionInfo.cs +++ b/src/SqlLocalDb/Interop/LocalDbVersionInfo.cs @@ -4,100 +4,99 @@ using System.Diagnostics; using System.Runtime.InteropServices; -namespace MartinCostello.SqlLocalDb.Interop +namespace MartinCostello.SqlLocalDb.Interop; + +/// +/// A structure representing version about a SQL Server LocalDB version. +/// +/// +/// See http://msdn.microsoft.com/en-us/library/hh234365.aspx. +/// +[DebuggerDisplay("{DebuggerDisplayName}")] +[StructLayout(LayoutKind.Sequential)] +internal struct LocalDbVersionInfo : ISqlLocalDbVersionInfo { /// - /// A structure representing version about a SQL Server LocalDB version. + /// The size of an unmanaged type in bytes. This field is read-only. + /// + internal static readonly int MarshalSize = Marshal.SizeOf(typeof(LocalDbVersionInfo)); + + /// + /// The size of the structure. /// /// - /// See http://msdn.microsoft.com/en-us/library/hh234365.aspx. + /// Maps to the cbLocalDBVersionInfoSize member. /// - [DebuggerDisplay("{DebuggerDisplayName}")] - [StructLayout(LayoutKind.Sequential)] - internal struct LocalDbVersionInfo : ISqlLocalDbVersionInfo - { - /// - /// The size of an unmanaged type in bytes. This field is read-only. - /// - internal static readonly int MarshalSize = Marshal.SizeOf(typeof(LocalDbVersionInfo)); - - /// - /// The size of the structure. - /// - /// - /// Maps to the cbLocalDBVersionInfoSize member. - /// - internal uint Size; + internal uint Size; - /// - /// The version name. - /// - /// - /// Maps to the wszVersion member. - /// - [MarshalAs(UnmanagedType.ByValArray, SizeConst = (LocalDbInstanceApi.MaximumInstanceVersionLength + 1) * sizeof(char))] - internal byte[] Name; + /// + /// The version name. + /// + /// + /// Maps to the wszVersion member. + /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = (LocalDbInstanceApi.MaximumInstanceVersionLength + 1) * sizeof(char))] + internal byte[] Name; - /// - /// Whether the instance files exist on disk. - /// - /// - /// Maps to the bExists member. - /// - internal bool Exists; + /// + /// Whether the instance files exist on disk. + /// + /// + /// Maps to the bExists member. + /// + internal bool Exists; - /// - /// The major version number. - /// - /// - /// Maps to the dwMajor member. - /// - internal uint Major; + /// + /// The major version number. + /// + /// + /// Maps to the dwMajor member. + /// + internal uint Major; - /// - /// The minor version number. - /// - /// - /// Maps to the dwMinor member. - /// - internal uint Minor; + /// + /// The minor version number. + /// + /// + /// Maps to the dwMinor member. + /// + internal uint Minor; - /// - /// The build version number. - /// - /// - /// Maps to the dwBuild member. - /// - internal uint Build; + /// + /// The build version number. + /// + /// + /// Maps to the dwBuild member. + /// + internal uint Build; - /// - /// The revision version number. - /// - /// - /// Maps to the dwRevision member. - /// - internal uint Revision; + /// + /// The revision version number. + /// + /// + /// Maps to the dwRevision member. + /// + internal uint Revision; - /// - /// Gets a value indicating whether the instance files exist on disk. - /// - bool ISqlLocalDbVersionInfo.Exists => Exists; + /// + /// Gets a value indicating whether the instance files exist on disk. + /// + bool ISqlLocalDbVersionInfo.Exists => Exists; - /// - /// Gets the version name. - /// - string ISqlLocalDbVersionInfo.Name => LocalDbInstanceApi.MarshalString(Name); + /// + /// Gets the version name. + /// + string ISqlLocalDbVersionInfo.Name => LocalDbInstanceApi.MarshalString(Name); - /// - /// Gets the version. - /// - Version ISqlLocalDbVersionInfo.Version => new Version((int)Major, (int)Minor, (int)Build, (int)Revision); + /// + /// Gets the version. + /// + Version ISqlLocalDbVersionInfo.Version => new Version((int)Major, (int)Minor, (int)Build, (int)Revision); - /// - /// Gets the name to display in the debugger. - /// - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] - private string DebuggerDisplayName => ((ISqlLocalDbVersionInfo)this).Name; - } + /// + /// Gets the name to display in the debugger. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + private string DebuggerDisplayName => ((ISqlLocalDbVersionInfo)this).Name; } diff --git a/src/SqlLocalDb/Interop/NativeMethods.cs b/src/SqlLocalDb/Interop/NativeMethods.cs index 0abf2927..d4c0194e 100644 --- a/src/SqlLocalDb/Interop/NativeMethods.cs +++ b/src/SqlLocalDb/Interop/NativeMethods.cs @@ -3,78 +3,77 @@ using System.Runtime.InteropServices; -namespace MartinCostello.SqlLocalDb.Interop +namespace MartinCostello.SqlLocalDb.Interop; + +/// +/// A class containing native P/Invoke methods. This class cannot be inherited. +/// +internal static class NativeMethods { /// - /// A class containing native P/Invoke methods. This class cannot be inherited. + /// This value represents the recommended maximum number of directories an application should include in its DLL search path. /// - internal static class NativeMethods - { - /// - /// This value represents the recommended maximum number of directories an application should include in its DLL search path. - /// - /// - /// Only supported on Windows Vista, 7, Server 2008 and Server 2008 R2 with KB2533623. - /// See https://docs.microsoft.com/en-gb/windows/desktop/api/libloaderapi/nf-libloaderapi-loadlibraryexa. - /// - internal const int LOAD_LIBRARY_SEARCH_DEFAULT_DIRS = 0x00001000; + /// + /// Only supported on Windows Vista, 7, Server 2008 and Server 2008 R2 with KB2533623. + /// See https://docs.microsoft.com/en-gb/windows/desktop/api/libloaderapi/nf-libloaderapi-loadlibraryexa. + /// + internal const int LOAD_LIBRARY_SEARCH_DEFAULT_DIRS = 0x00001000; - /// - /// The name of the Windows Kernel library. - /// - internal const string KernelLibName = "kernel32.dll"; + /// + /// The name of the Windows Kernel library. + /// + internal const string KernelLibName = "kernel32.dll"; - /// - /// Frees a specified library. - /// - /// The handle to the module to free. - /// Whether the library was successfully unloaded. - [DefaultDllImportSearchPaths(DllImportSearchPath.UserDirectories)] - [DllImport(KernelLibName)] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool FreeLibrary(IntPtr handle); + /// + /// Frees a specified library. + /// + /// The handle to the module to free. + /// Whether the library was successfully unloaded. + [DefaultDllImportSearchPaths(DllImportSearchPath.UserDirectories)] + [DllImport(KernelLibName)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool FreeLibrary(IntPtr handle); - /// - /// Retrieves the address of an exported function or variable from the specified dynamic-link library (DLL). - /// - /// A handle to the DLL module that contains the function or variable. - /// The function or variable name, or the function's ordinal value. - /// - /// If the function succeeds, the return value is the address of the exported function or variable. - /// If the function fails, the return value is . - /// - /// - /// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms683212%28v=vs.85%29.aspx. - /// + /// + /// Retrieves the address of an exported function or variable from the specified dynamic-link library (DLL). + /// + /// A handle to the DLL module that contains the function or variable. + /// The function or variable name, or the function's ordinal value. + /// + /// If the function succeeds, the return value is the address of the exported function or variable. + /// If the function fails, the return value is . + /// + /// + /// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms683212%28v=vs.85%29.aspx. + /// #pragma warning disable CA2101 - [DefaultDllImportSearchPaths(DllImportSearchPath.UserDirectories)] - [DllImport(KernelLibName, BestFitMapping = false, CharSet = CharSet.Ansi, ThrowOnUnmappableChar = true)] - internal static extern IntPtr GetProcAddress( - SafeLibraryHandle hModule, - [MarshalAs(UnmanagedType.LPStr)] string lpProcName); + [DefaultDllImportSearchPaths(DllImportSearchPath.UserDirectories)] + [DllImport(KernelLibName, BestFitMapping = false, CharSet = CharSet.Ansi, ThrowOnUnmappableChar = true)] + internal static extern IntPtr GetProcAddress( + SafeLibraryHandle hModule, + [MarshalAs(UnmanagedType.LPStr)] string lpProcName); #pragma warning restore CA2101 - /// - /// Loads the specified module into the address space of the calling process. - /// The specified module may cause other modules to be loaded. - /// - /// The name of the module. - /// This parameter is reserved for future use. It must be . - /// The action to be taken when loading the module. - /// - /// If the function succeeds, the return value is a handle to the module. - /// If the function fails, the return value is . - /// - /// - /// See https://docs.microsoft.com/en-gb/windows/desktop/api/libloaderapi/nf-libloaderapi-loadlibraryexa. - /// + /// + /// Loads the specified module into the address space of the calling process. + /// The specified module may cause other modules to be loaded. + /// + /// The name of the module. + /// This parameter is reserved for future use. It must be . + /// The action to be taken when loading the module. + /// + /// If the function succeeds, the return value is a handle to the module. + /// If the function fails, the return value is . + /// + /// + /// See https://docs.microsoft.com/en-gb/windows/desktop/api/libloaderapi/nf-libloaderapi-loadlibraryexa. + /// #pragma warning disable CA2101 - [DefaultDllImportSearchPaths(DllImportSearchPath.UserDirectories)] - [DllImport(KernelLibName, BestFitMapping = false, CharSet = CharSet.Ansi, SetLastError = true, ThrowOnUnmappableChar = true)] - internal static extern SafeLibraryHandle LoadLibraryEx( - [MarshalAs(UnmanagedType.LPStr)] string lpFileName, - IntPtr hFile, - int dwFlags); + [DefaultDllImportSearchPaths(DllImportSearchPath.UserDirectories)] + [DllImport(KernelLibName, BestFitMapping = false, CharSet = CharSet.Ansi, SetLastError = true, ThrowOnUnmappableChar = true)] + internal static extern SafeLibraryHandle LoadLibraryEx( + [MarshalAs(UnmanagedType.LPStr)] string lpFileName, + IntPtr hFile, + int dwFlags); #pragma warning restore CA2101 - } } diff --git a/src/SqlLocalDb/Interop/SafeLibraryHandle.cs b/src/SqlLocalDb/Interop/SafeLibraryHandle.cs index 7d466770..901e824e 100644 --- a/src/SqlLocalDb/Interop/SafeLibraryHandle.cs +++ b/src/SqlLocalDb/Interop/SafeLibraryHandle.cs @@ -3,30 +3,29 @@ using Microsoft.Win32.SafeHandles; -namespace MartinCostello.SqlLocalDb.Interop +namespace MartinCostello.SqlLocalDb.Interop; + +/// +/// A class that represents a handle to a library. This class cannot be inherited. +/// +internal sealed class SafeLibraryHandle : SafeHandleZeroOrMinusOneIsInvalid { /// - /// A class that represents a handle to a library. This class cannot be inherited. + /// Initializes a new instance of the class. /// - internal sealed class SafeLibraryHandle : SafeHandleZeroOrMinusOneIsInvalid + public SafeLibraryHandle() + : base(true) { - /// - /// Initializes a new instance of the class. - /// - public SafeLibraryHandle() - : base(true) - { - } - - /// - /// Executes the code required to free the handle. - /// - /// - /// if the handle is released successfully; - /// otherwise, in the event of a catastrophic failure, - /// . In this case, it generates a ReleaseHandleFailed - /// Managed Debugging Assistant. - /// - protected override bool ReleaseHandle() => NativeMethods.FreeLibrary(handle); } + + /// + /// Executes the code required to free the handle. + /// + /// + /// if the handle is released successfully; + /// otherwise, in the event of a catastrophic failure, + /// . In this case, it generates a ReleaseHandleFailed + /// Managed Debugging Assistant. + /// + protected override bool ReleaseHandle() => NativeMethods.FreeLibrary(handle); } diff --git a/src/SqlLocalDb/Interop/WindowsRegistry.cs b/src/SqlLocalDb/Interop/WindowsRegistry.cs index d998a15b..144785dc 100644 --- a/src/SqlLocalDb/Interop/WindowsRegistry.cs +++ b/src/SqlLocalDb/Interop/WindowsRegistry.cs @@ -3,21 +3,20 @@ using Microsoft.Win32; -namespace MartinCostello.SqlLocalDb.Interop +namespace MartinCostello.SqlLocalDb.Interop; + +/// +/// A class representing an implementation of for the Windows registry. This class cannot be inherited. +/// +internal sealed class WindowsRegistry : IRegistry { - /// - /// A class representing an implementation of for the Windows registry. This class cannot be inherited. - /// - internal sealed class WindowsRegistry : IRegistry - { - /// + /// #if NET5_0_OR_GREATER - [System.Runtime.Versioning.SupportedOSPlatform("windows")] + [System.Runtime.Versioning.SupportedOSPlatform("windows")] #endif - public IRegistryKey? OpenSubKey(string keyName) - { - RegistryKey? key = Registry.LocalMachine.OpenSubKey(keyName, writable: false); - return key == null ? null : new WindowsRegistryKey(key); - } + public IRegistryKey? OpenSubKey(string keyName) + { + RegistryKey? key = Registry.LocalMachine.OpenSubKey(keyName, writable: false); + return key == null ? null : new WindowsRegistryKey(key); } } diff --git a/src/SqlLocalDb/Interop/WindowsRegistryKey.cs b/src/SqlLocalDb/Interop/WindowsRegistryKey.cs index f1cafc20..1ee7fe33 100644 --- a/src/SqlLocalDb/Interop/WindowsRegistryKey.cs +++ b/src/SqlLocalDb/Interop/WindowsRegistryKey.cs @@ -4,54 +4,53 @@ using System.Diagnostics; using Microsoft.Win32; -namespace MartinCostello.SqlLocalDb.Interop +namespace MartinCostello.SqlLocalDb.Interop; + +/// +/// A class representing an implementation of for a Windows registry key. This class cannot be inherited. +/// +internal sealed class WindowsRegistryKey : IRegistryKey { /// - /// A class representing an implementation of for a Windows registry key. This class cannot be inherited. + /// The wrapped by the instance. This field is read-only. + /// + private readonly RegistryKey _key; + + /// + /// Initializes a new instance of the class. /// - internal sealed class WindowsRegistryKey : IRegistryKey + /// The to wrap. + internal WindowsRegistryKey(RegistryKey key) { - /// - /// The wrapped by the instance. This field is read-only. - /// - private readonly RegistryKey _key; - - /// - /// Initializes a new instance of the class. - /// - /// The to wrap. - internal WindowsRegistryKey(RegistryKey key) - { - Debug.Assert(key != null, "key cannot be null."); - _key = key!; - } - - /// + Debug.Assert(key != null, "key cannot be null."); + _key = key!; + } + + /// #if NET5_0_OR_GREATER - [System.Runtime.Versioning.SupportedOSPlatform("windows")] + [System.Runtime.Versioning.SupportedOSPlatform("windows")] #endif - void IDisposable.Dispose() => _key.Dispose(); + void IDisposable.Dispose() => _key.Dispose(); - /// + /// #if NET5_0_OR_GREATER - [System.Runtime.Versioning.SupportedOSPlatform("windows")] + [System.Runtime.Versioning.SupportedOSPlatform("windows")] #endif - public string[] GetSubKeyNames() => _key.GetSubKeyNames(); + public string[] GetSubKeyNames() => _key.GetSubKeyNames(); - /// + /// #if NET5_0_OR_GREATER - [System.Runtime.Versioning.SupportedOSPlatform("windows")] + [System.Runtime.Versioning.SupportedOSPlatform("windows")] #endif - public string? GetValue(string name) => _key.GetValue(name, null, RegistryValueOptions.None) as string; + public string? GetValue(string name) => _key.GetValue(name, null, RegistryValueOptions.None) as string; - /// + /// #if NET5_0_OR_GREATER - [System.Runtime.Versioning.SupportedOSPlatform("windows")] + [System.Runtime.Versioning.SupportedOSPlatform("windows")] #endif - public IRegistryKey? OpenSubKey(string keyName) - { - RegistryKey? key = _key.OpenSubKey(keyName); - return key == null ? null : new WindowsRegistryKey(key); - } + public IRegistryKey? OpenSubKey(string keyName) + { + RegistryKey? key = _key.OpenSubKey(keyName); + return key == null ? null : new WindowsRegistryKey(key); } } diff --git a/src/SqlLocalDb/SRHelper.cs b/src/SqlLocalDb/SRHelper.cs index 28b847a0..10d12273 100644 --- a/src/SqlLocalDb/SRHelper.cs +++ b/src/SqlLocalDb/SRHelper.cs @@ -1,31 +1,30 @@ // Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -namespace MartinCostello.SqlLocalDb +namespace MartinCostello.SqlLocalDb; + +/// +/// A static class containing helper methods for use with the class. +/// +internal static class SRHelper { /// - /// A static class containing helper methods for use with the class. + /// Replaces the format item in a specified string with the string representation + /// of a corresponding object in a specified array. /// - internal static class SRHelper - { - /// - /// Replaces the format item in a specified string with the string representation - /// of a corresponding object in a specified array. - /// - /// A composite format string. - /// An object array that contains zero or more objects to format. - /// - /// A copy of format in which the format items have been replaced by the string - /// representation of the corresponding objects in args. - /// - /// - /// or is null. - /// - /// - /// is invalid or the index of a format item is less than zero, - /// or greater than or equal to the length of the array. - /// - internal static string Format(string format, params object[] args) - => string.Format(SR.Culture, format, args); - } + /// A composite format string. + /// An object array that contains zero or more objects to format. + /// + /// A copy of format in which the format items have been replaced by the string + /// representation of the corresponding objects in args. + /// + /// + /// or is null. + /// + /// + /// is invalid or the index of a format item is less than zero, + /// or greater than or equal to the length of the array. + /// + internal static string Format(string format, params object[] args) + => string.Format(SR.Culture, format, args); } diff --git a/src/SqlLocalDb/SqlLocalDbApi.cs b/src/SqlLocalDb/SqlLocalDbApi.cs index 1be9abea..298441fc 100644 --- a/src/SqlLocalDb/SqlLocalDbApi.cs +++ b/src/SqlLocalDb/SqlLocalDbApi.cs @@ -9,1423 +9,1422 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; -namespace MartinCostello.SqlLocalDb +namespace MartinCostello.SqlLocalDb; + +/// +/// A class representing a wrapper to the SQL Server LocalDB Instance API. This class cannot be inherited. +/// +public sealed class SqlLocalDbApi : ISqlLocalDbApi, ISqlLocalDbApiAdapter, IDisposable { /// - /// A class representing a wrapper to the SQL Server LocalDB Instance API. This class cannot be inherited. + /// The name of the default instance in SQL LocalDB 2012. + /// + private const string DefaultInstanceName2012 = "v11.0"; + + /// + /// The name of the default instance in SQL LocalDB 2014 and later. + /// + private const string DefaultInstanceName2014AndLater = "MSSQLLocalDB"; + + /// + /// The maximum length of a SQL LocalDB instance name, in bytes. + /// + private const int MaxInstanceNameLength = (LocalDbInstanceApi.MaximumInstanceNameLength + 1) * sizeof(char); + + /// + /// The maximum length of a SQL LocalDB version string, in bytes. + /// + private const int MaxVersionLength = (LocalDbInstanceApi.MaximumInstanceVersionLength + 1) * sizeof(char); + + /// + /// The value to pass to functions which have a reserved parameter for future use. + /// + private const int ReservedValue = 0; + + /// + /// The native API. This field is read-only. + /// + private readonly LocalDbInstanceApi _api; + + /// + /// Whether the instance has been disposed of. + /// + private bool _disposed; + + /// + /// The available versions of SQL Server LocalDB installed on the local machine. /// - public sealed class SqlLocalDbApi : ISqlLocalDbApi, ISqlLocalDbApiAdapter, IDisposable - { - /// - /// The name of the default instance in SQL LocalDB 2012. - /// - private const string DefaultInstanceName2012 = "v11.0"; - - /// - /// The name of the default instance in SQL LocalDB 2014 and later. - /// - private const string DefaultInstanceName2014AndLater = "MSSQLLocalDB"; - - /// - /// The maximum length of a SQL LocalDB instance name, in bytes. - /// - private const int MaxInstanceNameLength = (LocalDbInstanceApi.MaximumInstanceNameLength + 1) * sizeof(char); - - /// - /// The maximum length of a SQL LocalDB version string, in bytes. - /// - private const int MaxVersionLength = (LocalDbInstanceApi.MaximumInstanceVersionLength + 1) * sizeof(char); - - /// - /// The value to pass to functions which have a reserved parameter for future use. - /// - private const int ReservedValue = 0; - - /// - /// The native API. This field is read-only. - /// - private readonly LocalDbInstanceApi _api; - - /// - /// Whether the instance has been disposed of. - /// - private bool _disposed; - - /// - /// The available versions of SQL Server LocalDB installed on the local machine. - /// #pragma warning disable SA1011 // See https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/2989 - private string[]? _versions; + private string[]? _versions; #pragma warning restore SA1011 - /// - /// The timeout for stopping an instance of LocalDB. - /// - private TimeSpan _stopTimeout; + /// + /// The timeout for stopping an instance of LocalDB. + /// + private TimeSpan _stopTimeout; - /// - /// Initializes a new instance of the class. - /// - public SqlLocalDbApi() - : this(new SqlLocalDbOptions(), NullLoggerFactory.Instance) - { - } + /// + /// Initializes a new instance of the class. + /// + public SqlLocalDbApi() + : this(new SqlLocalDbOptions(), NullLoggerFactory.Instance) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The to use. + /// + /// is . + /// + /// + /// did create the required loggers. + /// + public SqlLocalDbApi(ILoggerFactory loggerFactory) + : this(new SqlLocalDbOptions(), loggerFactory) + { + } - /// - /// Initializes a new instance of the class. - /// - /// The to use. - /// - /// is . - /// - /// - /// did create the required loggers. - /// - public SqlLocalDbApi(ILoggerFactory loggerFactory) - : this(new SqlLocalDbOptions(), loggerFactory) + /// + /// Initializes a new instance of the class. + /// + /// The to use. + /// The to use. + /// + /// or is . + /// + /// + /// did create the required loggers. + /// + public SqlLocalDbApi(SqlLocalDbOptions options, ILoggerFactory loggerFactory) + : this(options, new WindowsRegistry(), loggerFactory) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The to use. + /// The to use. + /// The to use. + /// + /// , or is . + /// + /// + /// did not create the required loggers. + /// + internal SqlLocalDbApi(SqlLocalDbOptions options, IRegistry registry, ILoggerFactory loggerFactory) + { + if (options == null) { + throw new ArgumentNullException(nameof(options)); } - /// - /// Initializes a new instance of the class. - /// - /// The to use. - /// The to use. - /// - /// or is . - /// - /// - /// did create the required loggers. - /// - public SqlLocalDbApi(SqlLocalDbOptions options, ILoggerFactory loggerFactory) - : this(options, new WindowsRegistry(), loggerFactory) + if (registry == null) { + throw new ArgumentNullException(nameof(registry)); } - /// - /// Initializes a new instance of the class. - /// - /// The to use. - /// The to use. - /// The to use. - /// - /// , or is . - /// - /// - /// did not create the required loggers. - /// - internal SqlLocalDbApi(SqlLocalDbOptions options, IRegistry registry, ILoggerFactory loggerFactory) + LoggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory)); + +#pragma warning disable CA1508 + Logger = loggerFactory.CreateLogger() ?? throw new InvalidOperationException(SRHelper.Format(SR.SqlLocalDbApi_NoLoggerFormat, nameof(SqlLocalDbApi))); + var apiLogger = loggerFactory.CreateLogger() ?? throw new InvalidOperationException(SRHelper.Format(SR.SqlLocalDbApi_NoLoggerFormat, nameof(LocalDbInstanceApi))); +#pragma warning restore CA1508 + + AutomaticallyDeleteInstanceFiles = options.AutomaticallyDeleteInstanceFiles; + LanguageId = options.LanguageId; + StopOptions = options.StopOptions; + StopTimeout = options.StopTimeout; + + _api = new LocalDbInstanceApi(options.NativeApiOverrideVersion, registry, apiLogger); + } + + /// + /// Gets or sets a value indicating whether to automatically delete the + /// files associated with SQL LocalDB instances when they are deleted. + /// + /// + /// Setting the value of this property affects the behavior of all delete + /// operations in the current unless the overloads + /// of and are + /// used. The default value is , unless overridden + /// by the SQLLocalDB:AutomaticallyDeleteInstanceFiles application configuration setting. + /// + public bool AutomaticallyDeleteInstanceFiles { get; set; } + + /// + /// Gets the name of the default SQL LocalDB instance. + /// + public string DefaultInstanceName + { + get { - if (options == null) + // Force the native API to be loaded so we can determine its version + if (!IsLocalDBInstalled()) { - throw new ArgumentNullException(nameof(options)); + // It isn't installed, so don't assume anything + return string.Empty; } - if (registry == null) + if (_api.NativeApiVersion!.Major == 11) { - throw new ArgumentNullException(nameof(registry)); + return DefaultInstanceName2012; } - LoggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory)); + // Provided Microsoft do not change the default name again this should work for all versions 12.0+ + return DefaultInstanceName2014AndLater; + } + } -#pragma warning disable CA1508 - Logger = loggerFactory.CreateLogger() ?? throw new InvalidOperationException(SRHelper.Format(SR.SqlLocalDbApi_NoLoggerFormat, nameof(SqlLocalDbApi))); - var apiLogger = loggerFactory.CreateLogger() ?? throw new InvalidOperationException(SRHelper.Format(SR.SqlLocalDbApi_NoLoggerFormat, nameof(LocalDbInstanceApi))); -#pragma warning restore CA1508 + /// + /// Gets or sets the locale ID (LCID) to use for formatting error messages. + /// + /// + /// The default value for this property is zero, in which case the Win32 FormatMessage language + /// order is used. This property is provided for integrators to specifically override the language used from + /// the defaults used by the local installed operating system. + /// + public int LanguageId { get; set; } - AutomaticallyDeleteInstanceFiles = options.AutomaticallyDeleteInstanceFiles; - LanguageId = options.LanguageId; - StopOptions = options.StopOptions; - StopTimeout = options.StopTimeout; + /// + /// Gets the version string for the latest installed version of SQL Server LocalDB. + /// + /// + /// No versions of SQL Server LocalDB are installed on the local machine. + /// + /// + /// The method is called from a non-Windows operating system. + /// + public string LatestVersion + { + get + { + EnsurePlatformSupported(); - _api = new LocalDbInstanceApi(options.NativeApiOverrideVersion, registry, apiLogger); - } + // Access through property to ensure initialized + IReadOnlyList versions = Versions; - /// - /// Gets or sets a value indicating whether to automatically delete the - /// files associated with SQL LocalDB instances when they are deleted. - /// - /// - /// Setting the value of this property affects the behavior of all delete - /// operations in the current unless the overloads - /// of and are - /// used. The default value is , unless overridden - /// by the SQLLocalDB:AutomaticallyDeleteInstanceFiles application configuration setting. - /// - public bool AutomaticallyDeleteInstanceFiles { get; set; } - - /// - /// Gets the name of the default SQL LocalDB instance. - /// - public string DefaultInstanceName - { - get + if (versions.Count < 1) { - // Force the native API to be loaded so we can determine its version - if (!IsLocalDBInstalled()) - { - // It isn't installed, so don't assume anything - return string.Empty; - } + string message = SRHelper.Format(SR.SqlLocalDbApi_NoVersionsFormat, Environment.MachineName); + throw new InvalidOperationException(message); + } - if (_api.NativeApiVersion!.Major == 11) - { - return DefaultInstanceName2012; - } + // Return the version with the highest number + return versions + .Select((p) => new Version(p)) + .OrderBy((p) => p) + .Last() + .ToString(); + } + } - // Provided Microsoft do not change the default name again this should work for all versions 12.0+ - return DefaultInstanceName2014AndLater; - } + /// + /// Gets or sets the options to use when stopping instances of SQL LocalDB. + /// + public StopInstanceOptions StopOptions { get; set; } + + /// + /// Gets or sets the default timeout to use when + /// stopping instances of SQL LocalDB. + /// + /// + /// is less than . + /// + public TimeSpan StopTimeout + { + get + { + return _stopTimeout; } - /// - /// Gets or sets the locale ID (LCID) to use for formatting error messages. - /// - /// - /// The default value for this property is zero, in which case the Win32 FormatMessage language - /// order is used. This property is provided for integrators to specifically override the language used from - /// the defaults used by the local installed operating system. - /// - public int LanguageId { get; set; } - - /// - /// Gets the version string for the latest installed version of SQL Server LocalDB. - /// - /// - /// No versions of SQL Server LocalDB are installed on the local machine. - /// - /// - /// The method is called from a non-Windows operating system. - /// - public string LatestVersion + set { - get + if (value < TimeSpan.Zero) { - EnsurePlatformSupported(); - - // Access through property to ensure initialized - IReadOnlyList versions = Versions; - - if (versions.Count < 1) - { - string message = SRHelper.Format(SR.SqlLocalDbApi_NoVersionsFormat, Environment.MachineName); - throw new InvalidOperationException(message); - } - - // Return the version with the highest number - return versions - .Select((p) => new Version(p)) - .OrderBy((p) => p) - .Last() - .ToString(); + string message = SRHelper.Format(SR.SqlLocalDbApi_TimeoutTooSmallFormat, nameof(value)); + throw new ArgumentOutOfRangeException(nameof(value), value, message); } + + _stopTimeout = value; } + } - /// - /// Gets or sets the options to use when stopping instances of SQL LocalDB. - /// - public StopInstanceOptions StopOptions { get; set; } - - /// - /// Gets or sets the default timeout to use when - /// stopping instances of SQL LocalDB. - /// - /// - /// is less than . - /// - public TimeSpan StopTimeout + /// + /// Gets an of containing + /// the available versions of SQL LocalDB. + /// + /// + /// SQL Server LocalDB is not installed on the local machine. + /// + /// + /// The installed versions of SQL LocalDB could not be determined. + /// + public IReadOnlyList Versions + { + get { - get + if (!IsWindows) { - return _stopTimeout; + return Array.Empty(); } - set + if (_versions == null) { - if (value < TimeSpan.Zero) - { - string message = SRHelper.Format(SR.SqlLocalDbApi_TimeoutTooSmallFormat, nameof(value)); - throw new ArgumentOutOfRangeException(nameof(value), value, message); - } - - _stopTimeout = value; + // Use lazy initialization to allow some functionality to be + // accessed regardless of whether LocalDB is installed + _versions = GetLocalDbVersions(); } + + return (string[])_versions.Clone(); } + } - /// - /// Gets an of containing - /// the available versions of SQL LocalDB. - /// - /// - /// SQL Server LocalDB is not installed on the local machine. - /// - /// - /// The installed versions of SQL LocalDB could not be determined. - /// - public IReadOnlyList Versions - { - get - { - if (!IsWindows) - { - return Array.Empty(); - } + /// + ISqlLocalDbApi ISqlLocalDbApiAdapter.LocalDb => this; - if (_versions == null) - { - // Use lazy initialization to allow some functionality to be - // accessed regardless of whether LocalDB is installed - _versions = GetLocalDbVersions(); - } + /// + /// Gets a value indicating whether the executing platform is Microsoft Windows. + /// + internal static bool IsWindows { get; } = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); - return (string[])_versions.Clone(); - } - } + /// + /// Gets the to use. + /// + internal ILoggerFactory LoggerFactory { get; } - /// - ISqlLocalDbApi ISqlLocalDbApiAdapter.LocalDb => this; - - /// - /// Gets a value indicating whether the executing platform is Microsoft Windows. - /// - internal static bool IsWindows { get; } = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); - - /// - /// Gets the to use. - /// - internal ILoggerFactory LoggerFactory { get; } - - /// - /// Gets the to use. - /// - private ILogger Logger { get; } - - /// - /// Gets the full path of the directory containing the SQL LocalDB instance files for the current user. - /// - /// - /// The full path of the directory containing the SQL LocalDB instance files for the current user. - /// - /// - /// The folder usually used to store SQL LocalDB instance files is %LOCALAPPDATA%\Microsoft\Microsoft SQL Server Local DB\Instances. - /// - public static string GetInstancesFolderPath() + /// + /// Gets the to use. + /// + private ILogger Logger { get; } + + /// + /// Gets the full path of the directory containing the SQL LocalDB instance files for the current user. + /// + /// + /// The full path of the directory containing the SQL LocalDB instance files for the current user. + /// + /// + /// The folder usually used to store SQL LocalDB instance files is %LOCALAPPDATA%\Microsoft\Microsoft SQL Server Local DB\Instances. + /// + public static string GetInstancesFolderPath() + { + return Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), + "Microsoft", + "Microsoft SQL Server Local DB", + "Instances"); + } + + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Creates a new instance of SQL Server LocalDB. + /// + /// The name of the LocalDB instance. + /// + /// An containing information about the instance that was created. + /// + /// + /// is . + /// + /// + /// No versions of SQL Server LocalDB are installed on the local machine. + /// + /// + /// The method is called from a non-Windows operating system. + /// + /// + /// The SQL Server LocalDB instance specified by could + /// not be stopped or the installed versions of SQL LocalDB could not be determined. + /// + public ISqlLocalDbInstanceInfo CreateInstance(string instanceName) => CreateInstance(instanceName, LatestVersion); + + /// + /// Creates a new instance of SQL Server LocalDB. + /// + /// The name of the LocalDB instance. + /// The version of SQL Server LocalDB to use. + /// + /// An containing information about the instance that was created. + /// + /// + /// or is . + /// + /// + /// SQL Server LocalDB is not installed on the local machine. + /// + /// + /// The method is called from a non-Windows operating system. + /// + /// + /// The SQL Server LocalDB instance specified by and could not be created. + /// + public ISqlLocalDbInstanceInfo CreateInstance(string instanceName, string version) + { + if (instanceName == null) { - return Path.Combine( - Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), - "Microsoft", - "Microsoft SQL Server Local DB", - "Instances"); + throw new ArgumentNullException(nameof(instanceName)); } - /// - public void Dispose() + if (version == null) { - Dispose(true); - GC.SuppressFinalize(this); + throw new ArgumentNullException(nameof(version)); } - /// - /// Creates a new instance of SQL Server LocalDB. - /// - /// The name of the LocalDB instance. - /// - /// An containing information about the instance that was created. - /// - /// - /// is . - /// - /// - /// No versions of SQL Server LocalDB are installed on the local machine. - /// - /// - /// The method is called from a non-Windows operating system. - /// - /// - /// The SQL Server LocalDB instance specified by could - /// not be stopped or the installed versions of SQL LocalDB could not be determined. - /// - public ISqlLocalDbInstanceInfo CreateInstance(string instanceName) => CreateInstance(instanceName, LatestVersion); - - /// - /// Creates a new instance of SQL Server LocalDB. - /// - /// The name of the LocalDB instance. - /// The version of SQL Server LocalDB to use. - /// - /// An containing information about the instance that was created. - /// - /// - /// or is . - /// - /// - /// SQL Server LocalDB is not installed on the local machine. - /// - /// - /// The method is called from a non-Windows operating system. - /// - /// - /// The SQL Server LocalDB instance specified by and could not be created. - /// - public ISqlLocalDbInstanceInfo CreateInstance(string instanceName, string version) - { - if (instanceName == null) - { - throw new ArgumentNullException(nameof(instanceName)); - } + Logger.CreatingInstance(instanceName, version); - if (version == null) - { - throw new ArgumentNullException(nameof(version)); - } + InvokeThrowOnError( + () => _api.CreateInstance(version, instanceName, ReservedValue), + EventIds.CreatingInstanceFailed, + instanceName); - Logger.CreatingInstance(instanceName, version); + Logger.CreatedInstance(instanceName, version); - InvokeThrowOnError( - () => _api.CreateInstance(version, instanceName, ReservedValue), - EventIds.CreatingInstanceFailed, - instanceName); + return GetInstanceInfo(instanceName); + } - Logger.CreatedInstance(instanceName, version); + /// + /// Deletes the specified SQL Server LocalDB instance. + /// + /// + /// The name of the LocalDB instance to delete. + /// + /// + /// is . + /// + /// + /// SQL Server LocalDB is not installed on the local machine. + /// + /// + /// The method is called from a non-Windows operating system. + /// + /// + /// The SQL Server LocalDB instance specified by could not be deleted. + /// + public void DeleteInstance(string instanceName) => DeleteInstance(instanceName, deleteFiles: AutomaticallyDeleteInstanceFiles); - return GetInstanceInfo(instanceName); - } + /// + /// Deletes the specified SQL Server LocalDB instance. + /// + /// + /// The name of the LocalDB instance to delete. + /// + /// + /// Whether to delete the file(s) associated with the SQL LocalDB instance. + /// + /// + /// is . + /// + /// + /// SQL Server LocalDB is not installed on the local machine. + /// + /// + /// The method is called from a non-Windows operating system. + /// + /// + /// The SQL Server LocalDB instance specified by could not be deleted. + /// + public void DeleteInstance(string instanceName, bool deleteFiles) + { + DeleteInstanceInternal(instanceName, throwIfNotFound: true, deleteFiles: deleteFiles); + } - /// - /// Deletes the specified SQL Server LocalDB instance. - /// - /// - /// The name of the LocalDB instance to delete. - /// - /// - /// is . - /// - /// - /// SQL Server LocalDB is not installed on the local machine. - /// - /// - /// The method is called from a non-Windows operating system. - /// - /// - /// The SQL Server LocalDB instance specified by could not be deleted. - /// - public void DeleteInstance(string instanceName) => DeleteInstance(instanceName, deleteFiles: AutomaticallyDeleteInstanceFiles); - - /// - /// Deletes the specified SQL Server LocalDB instance. - /// - /// - /// The name of the LocalDB instance to delete. - /// - /// - /// Whether to delete the file(s) associated with the SQL LocalDB instance. - /// - /// - /// is . - /// - /// - /// SQL Server LocalDB is not installed on the local machine. - /// - /// - /// The method is called from a non-Windows operating system. - /// - /// - /// The SQL Server LocalDB instance specified by could not be deleted. - /// - public void DeleteInstance(string instanceName, bool deleteFiles) - { - DeleteInstanceInternal(instanceName, throwIfNotFound: true, deleteFiles: deleteFiles); - } + /// + /// Deletes all user instances of SQL LocalDB on the current machine. + /// + /// + /// The number of user instances of SQL LocalDB that were deleted. + /// + /// + /// The default instance(s) of any version(s) of SQL LocalDB that are + /// installed on the local machine are not deleted. + /// + /// + /// SQL Server LocalDB is not installed on the local machine. + /// + /// + /// The method is called from a non-Windows operating system. + /// + public int DeleteUserInstances() => DeleteUserInstances(deleteFiles: AutomaticallyDeleteInstanceFiles); - /// - /// Deletes all user instances of SQL LocalDB on the current machine. - /// - /// - /// The number of user instances of SQL LocalDB that were deleted. - /// - /// - /// The default instance(s) of any version(s) of SQL LocalDB that are - /// installed on the local machine are not deleted. - /// - /// - /// SQL Server LocalDB is not installed on the local machine. - /// - /// - /// The method is called from a non-Windows operating system. - /// - public int DeleteUserInstances() => DeleteUserInstances(deleteFiles: AutomaticallyDeleteInstanceFiles); - - /// - /// Deletes all user instances of SQL LocalDB on the current machine, - /// optionally also deleting all of the file(s) associated with the - /// SQL LocalDB user instance(s) from disk. - /// - /// - /// Whether to delete the file(s) associated with the SQL LocalDB user instance(s). - /// - /// - /// The number of user instances of SQL LocalDB that were deleted. - /// - /// - /// The default instance(s) of any version(s) of SQL LocalDB that are - /// installed on the local machine are not deleted. - /// - /// - /// SQL Server LocalDB is not installed on the local machine. - /// - /// - /// The method is called from a non-Windows operating system. - /// - public int DeleteUserInstances(bool deleteFiles) - { - int instancesDeleted = 0; + /// + /// Deletes all user instances of SQL LocalDB on the current machine, + /// optionally also deleting all of the file(s) associated with the + /// SQL LocalDB user instance(s) from disk. + /// + /// + /// Whether to delete the file(s) associated with the SQL LocalDB user instance(s). + /// + /// + /// The number of user instances of SQL LocalDB that were deleted. + /// + /// + /// The default instance(s) of any version(s) of SQL LocalDB that are + /// installed on the local machine are not deleted. + /// + /// + /// SQL Server LocalDB is not installed on the local machine. + /// + /// + /// The method is called from a non-Windows operating system. + /// + public int DeleteUserInstances(bool deleteFiles) + { + int instancesDeleted = 0; - IReadOnlyList instanceNames = GetInstanceNames(); + IReadOnlyList instanceNames = GetInstanceNames(); - foreach (string instanceName in instanceNames) + foreach (string instanceName in instanceNames) + { + ISqlLocalDbInstanceInfo info = GetInstanceInfo(instanceName); + + // Do not try to delete automatic instances. + // These are the default instances created for each version. + // As of SQL LocalDB 2014, the default instance is named 'MSSQLLocalDB'. + if (!info.Exists || + info.IsAutomatic || + string.Equals(info.Name, DefaultInstanceName2014AndLater, StringComparison.Ordinal)) { - ISqlLocalDbInstanceInfo info = GetInstanceInfo(instanceName); - - // Do not try to delete automatic instances. - // These are the default instances created for each version. - // As of SQL LocalDB 2014, the default instance is named 'MSSQLLocalDB'. - if (!info.Exists || - info.IsAutomatic || - string.Equals(info.Name, DefaultInstanceName2014AndLater, StringComparison.Ordinal)) - { - continue; - } + continue; + } - // In some cases, SQL LocalDB may report instance names in calls - // to enumerate the instances that do not actually exist. Presumably - // this can occur if the installation/instances become corrupted. - // Such failures to delete an instance should be ignored - try + // In some cases, SQL LocalDB may report instance names in calls + // to enumerate the instances that do not actually exist. Presumably + // this can occur if the installation/instances become corrupted. + // Such failures to delete an instance should be ignored + try + { + if (DeleteInstanceInternal(instanceName, throwIfNotFound: false, deleteFiles: deleteFiles)) { - if (DeleteInstanceInternal(instanceName, throwIfNotFound: false, deleteFiles: deleteFiles)) - { - instancesDeleted++; - } + instancesDeleted++; } - catch (SqlLocalDbException ex) + } + catch (SqlLocalDbException ex) + { + if (ex.ErrorCode == SqlLocalDbErrors.InstanceBusy) { - if (ex.ErrorCode == SqlLocalDbErrors.InstanceBusy) - { - Logger.DeletingInstanceFailedAsInUse(ex, ex.InstanceName); - continue; - } - - throw; + Logger.DeletingInstanceFailedAsInUse(ex, ex.InstanceName); + continue; } - } - return instancesDeleted; + throw; + } } - /// - /// Returns information about the specified LocalDB instance. - /// - /// The name of the LocalDB instance to get the information for. - /// - /// An instance of containing information - /// about the LocalDB instance specified by . - /// - /// - /// is . - /// - /// - /// SQL Server LocalDB is not installed on the local machine. - /// - /// - /// The method is called from a non-Windows operating system. - /// - /// - /// The information for the SQL Server LocalDB instance specified by could not obtained. - /// - public ISqlLocalDbInstanceInfo GetInstanceInfo(string instanceName) + return instancesDeleted; + } + + /// + /// Returns information about the specified LocalDB instance. + /// + /// The name of the LocalDB instance to get the information for. + /// + /// An instance of containing information + /// about the LocalDB instance specified by . + /// + /// + /// is . + /// + /// + /// SQL Server LocalDB is not installed on the local machine. + /// + /// + /// The method is called from a non-Windows operating system. + /// + /// + /// The information for the SQL Server LocalDB instance specified by could not obtained. + /// + public ISqlLocalDbInstanceInfo GetInstanceInfo(string instanceName) + { + if (instanceName == null) { - if (instanceName == null) - { - throw new ArgumentNullException(nameof(instanceName)); - } + throw new ArgumentNullException(nameof(instanceName)); + } - Logger.GettingInstanceInfo(instanceName); + Logger.GettingInstanceInfo(instanceName); - LocalDbInstanceInfo info; + LocalDbInstanceInfo info; - int size = LocalDbInstanceInfo.MarshalSize; - IntPtr ptrInfo = Marshal.AllocHGlobal(size); + int size = LocalDbInstanceInfo.MarshalSize; + IntPtr ptrInfo = Marshal.AllocHGlobal(size); - try - { - InvokeThrowOnError( - () => _api.GetInstanceInfo(instanceName, ptrInfo, size), - EventIds.GettingInstanceInfoFailed, - instanceName); + try + { + InvokeThrowOnError( + () => _api.GetInstanceInfo(instanceName, ptrInfo, size), + EventIds.GettingInstanceInfoFailed, + instanceName); - info = MarshalStruct(ptrInfo); - } - finally - { - Marshal.FreeHGlobal(ptrInfo); - } + info = MarshalStruct(ptrInfo); + } + finally + { + Marshal.FreeHGlobal(ptrInfo); + } - Logger.GotInstanceInfo(instanceName); + Logger.GotInstanceInfo(instanceName); - var result = new SqlLocalDbInstanceInfo(this); + var result = new SqlLocalDbInstanceInfo(this); - result.Update(info); + result.Update(info); - return result; - } + return result; + } - /// - /// Returns the names of all the SQL Server LocalDB instances for the current user. - /// - /// - /// The names of the the SQL Server LocalDB instances for the current user. - /// - /// - /// SQL Server LocalDB is not installed on the local machine. - /// - /// - /// The method is called from a non-Windows operating system. - /// - /// - /// The SQL Server LocalDB instance names could not be determined. - /// - public IReadOnlyList GetInstanceNames() - { - EnsurePlatformSupported(); + /// + /// Returns the names of all the SQL Server LocalDB instances for the current user. + /// + /// + /// The names of the the SQL Server LocalDB instances for the current user. + /// + /// + /// SQL Server LocalDB is not installed on the local machine. + /// + /// + /// The method is called from a non-Windows operating system. + /// + /// + /// The SQL Server LocalDB instance names could not be determined. + /// + public IReadOnlyList GetInstanceNames() + { + EnsurePlatformSupported(); - Logger.GettingInstanceNames(); + Logger.GettingInstanceNames(); - // Query the LocalDB API to get the number of instances - int count = 0; - int hr = _api.GetInstanceNames(IntPtr.Zero, ref count); + // Query the LocalDB API to get the number of instances + int count = 0; + int hr = _api.GetInstanceNames(IntPtr.Zero, ref count); - if (hr != 0 && - hr != SqlLocalDbErrors.InsufficientBuffer) - { - throw GetLocalDbError(hr, EventIds.GettingInstanceNamesFailed); - } + if (hr != 0 && + hr != SqlLocalDbErrors.InsufficientBuffer) + { + throw GetLocalDbError(hr, EventIds.GettingInstanceNamesFailed); + } - string[] names; + string[] names; - // Allocate enough memory to receive the instance name array - int nameLength = MaxInstanceNameLength; - IntPtr ptrNames = Marshal.AllocHGlobal(nameLength * count); + // Allocate enough memory to receive the instance name array + int nameLength = MaxInstanceNameLength; + IntPtr ptrNames = Marshal.AllocHGlobal(nameLength * count); - try - { - InvokeThrowOnError( - () => _api.GetInstanceNames(ptrNames, ref count), - EventIds.GettingInstanceNamesFailed); + try + { + InvokeThrowOnError( + () => _api.GetInstanceNames(ptrNames, ref count), + EventIds.GettingInstanceNamesFailed); - // Read the instance names back from unmanaged memory - names = MarshalStringArray(ptrNames, nameLength, count); - } - finally - { - Marshal.FreeHGlobal(ptrNames); - } + // Read the instance names back from unmanaged memory + names = MarshalStringArray(ptrNames, nameLength, count); + } + finally + { + Marshal.FreeHGlobal(ptrNames); + } - Logger.GotInstanceNames(names.Length); + Logger.GotInstanceNames(names.Length); - return names; - } + return names; + } - /// - /// Returns information about the specified LocalDB version. - /// - /// The name of the LocalDB version to get the information for. - /// - /// An instance of containing information - /// about the LocalDB version specified by . - /// - /// - /// is . - /// - /// - /// SQL Server LocalDB is not installed on the local machine. - /// - /// - /// The method is called from a non-Windows operating system. - /// - /// - /// The information for the SQL Server LocalDB version specified by could not be obtained. - /// - public ISqlLocalDbVersionInfo GetVersionInfo(string version) + /// + /// Returns information about the specified LocalDB version. + /// + /// The name of the LocalDB version to get the information for. + /// + /// An instance of containing information + /// about the LocalDB version specified by . + /// + /// + /// is . + /// + /// + /// SQL Server LocalDB is not installed on the local machine. + /// + /// + /// The method is called from a non-Windows operating system. + /// + /// + /// The information for the SQL Server LocalDB version specified by could not be obtained. + /// + public ISqlLocalDbVersionInfo GetVersionInfo(string version) + { + if (version == null) { - if (version == null) - { - throw new ArgumentNullException(nameof(version)); - } + throw new ArgumentNullException(nameof(version)); + } - Logger.GettingVersionInfo(version); + Logger.GettingVersionInfo(version); - LocalDbVersionInfo info; + LocalDbVersionInfo info; - int size = LocalDbVersionInfo.MarshalSize; - IntPtr ptrInfo = Marshal.AllocHGlobal(size); + int size = LocalDbVersionInfo.MarshalSize; + IntPtr ptrInfo = Marshal.AllocHGlobal(size); - try - { - InvokeThrowOnError( - () => _api.GetVersionInfo(version, ptrInfo, size), - EventIds.GettingVersionInfoFailed); + try + { + InvokeThrowOnError( + () => _api.GetVersionInfo(version, ptrInfo, size), + EventIds.GettingVersionInfoFailed); - info = MarshalStruct(ptrInfo); - } - finally - { - Marshal.FreeHGlobal(ptrInfo); - } + info = MarshalStruct(ptrInfo); + } + finally + { + Marshal.FreeHGlobal(ptrInfo); + } - Logger.GotVersionInfo(version); + Logger.GotVersionInfo(version); - var result = new SqlLocalDbVersionInfo(); + var result = new SqlLocalDbVersionInfo(); - result.Update(info); + result.Update(info); - return result; - } + return result; + } - /// - /// Returns whether the specified LocalDB instance exists. - /// - /// The name of the LocalDB instance to check for existence. - /// - /// if the LocalDB instance specified by - /// exists; otherwise . - /// - /// - /// is . - /// - /// - /// SQL Server LocalDB is not installed on the local machine. - /// - /// - /// The method is called from a non-Windows operating system. - /// - /// - /// Whether the SQL Server LocalDB instance specified by exists could not be determined. - /// - public bool InstanceExists(string instanceName) + /// + /// Returns whether the specified LocalDB instance exists. + /// + /// The name of the LocalDB instance to check for existence. + /// + /// if the LocalDB instance specified by + /// exists; otherwise . + /// + /// + /// is . + /// + /// + /// SQL Server LocalDB is not installed on the local machine. + /// + /// + /// The method is called from a non-Windows operating system. + /// + /// + /// Whether the SQL Server LocalDB instance specified by exists could not be determined. + /// + public bool InstanceExists(string instanceName) + { + try { - try - { - return GetInstanceInfo(instanceName).Exists; - } - catch (SqlLocalDbException ex) when (ex.ErrorCode == SqlLocalDbErrors.UnknownInstance) - { - return false; - } + return GetInstanceInfo(instanceName).Exists; } - - /// - /// Returns whether SQL LocalDB is installed on the current machine. - /// - /// - /// if SQL Server LocalDB is installed on the - /// current machine; otherwise . - /// - public bool IsLocalDBInstalled() + catch (SqlLocalDbException ex) when (ex.ErrorCode == SqlLocalDbErrors.UnknownInstance) { - // SQL LocalDB is only supported on Windows, so shortcut - if (!IsWindows) - { - return false; - } + return false; + } + } - // Call one of the "get info" functions with a zero buffer. - // If LocalDB is installed, it will return a "buffer too small" HRESULT, - // otherwise it will return the "not installed" HRESULT. - int notUsed = 0; - int hr = _api.GetVersions(IntPtr.Zero, ref notUsed); - return hr != SqlLocalDbErrors.NotInstalled; + /// + /// Returns whether SQL LocalDB is installed on the current machine. + /// + /// + /// if SQL Server LocalDB is installed on the + /// current machine; otherwise . + /// + public bool IsLocalDBInstalled() + { + // SQL LocalDB is only supported on Windows, so shortcut + if (!IsWindows) + { + return false; } - /// - /// Shares the specified SQL Server LocalDB instance with other - /// users of the computer, using the specified shared name. - /// - /// The SID of the instance owner. - /// The private name for the LocalDB instance to share. - /// The shared name for the LocalDB instance to share as. - /// - /// , or is . - /// - /// - /// SQL Server LocalDB is not installed on the local machine. - /// - /// - /// The method is called from a non-Windows operating system. - /// - /// - /// The SQL Server LocalDB instance specified by could not be shared. - /// - public void ShareInstance( - string ownerSid, - string instanceName, - string sharedInstanceName) + // Call one of the "get info" functions with a zero buffer. + // If LocalDB is installed, it will return a "buffer too small" HRESULT, + // otherwise it will return the "not installed" HRESULT. + int notUsed = 0; + int hr = _api.GetVersions(IntPtr.Zero, ref notUsed); + return hr != SqlLocalDbErrors.NotInstalled; + } + + /// + /// Shares the specified SQL Server LocalDB instance with other + /// users of the computer, using the specified shared name. + /// + /// The SID of the instance owner. + /// The private name for the LocalDB instance to share. + /// The shared name for the LocalDB instance to share as. + /// + /// , or is . + /// + /// + /// SQL Server LocalDB is not installed on the local machine. + /// + /// + /// The method is called from a non-Windows operating system. + /// + /// + /// The SQL Server LocalDB instance specified by could not be shared. + /// + public void ShareInstance( + string ownerSid, + string instanceName, + string sharedInstanceName) + { + if (ownerSid == null) { - if (ownerSid == null) - { - throw new ArgumentNullException(nameof(ownerSid)); - } + throw new ArgumentNullException(nameof(ownerSid)); + } - if (instanceName == null) - { - throw new ArgumentNullException(nameof(instanceName)); - } + if (instanceName == null) + { + throw new ArgumentNullException(nameof(instanceName)); + } - if (sharedInstanceName == null) - { - throw new ArgumentNullException(nameof(sharedInstanceName)); - } + if (sharedInstanceName == null) + { + throw new ArgumentNullException(nameof(sharedInstanceName)); + } - EnsurePlatformSupported(); + EnsurePlatformSupported(); - if (instanceName.Length == 0) - { - // There is a bug in the SQL LocalDB native API that - // lets you share out an instance with no name, which - // then causes "interesting" results when using the other - // API functions on it. Block this explicitly to stop - // callers messing up their LocalDB instance. - throw new ArgumentException(SR.SqlLocalDbApi_NoInstanceName, nameof(instanceName)); - } + if (instanceName.Length == 0) + { + // There is a bug in the SQL LocalDB native API that + // lets you share out an instance with no name, which + // then causes "interesting" results when using the other + // API functions on it. Block this explicitly to stop + // callers messing up their LocalDB instance. + throw new ArgumentException(SR.SqlLocalDbApi_NoInstanceName, nameof(instanceName)); + } - Logger.SharingInstance(instanceName, ownerSid, sharedInstanceName); + Logger.SharingInstance(instanceName, ownerSid, sharedInstanceName); - // Get the binary version of the SID from its string + // Get the binary version of the SID from its string #pragma warning disable CA1416 - byte[] binaryForm = GetOwnerSidAsByteArray(ownerSid); + byte[] binaryForm = GetOwnerSidAsByteArray(ownerSid); #pragma warning restore CA1416 - IntPtr ptrSid = Marshal.AllocHGlobal(binaryForm.Length); + IntPtr ptrSid = Marshal.AllocHGlobal(binaryForm.Length); - try - { - // Copy the SID binary form to unmanaged memory - Marshal.Copy(binaryForm, 0, ptrSid, binaryForm.Length); + try + { + // Copy the SID binary form to unmanaged memory + Marshal.Copy(binaryForm, 0, ptrSid, binaryForm.Length); - InvokeThrowOnError( - () => _api.ShareInstance(ptrSid, instanceName, sharedInstanceName, ReservedValue), - EventIds.SharingInstanceFailed, - instanceName); + InvokeThrowOnError( + () => _api.ShareInstance(ptrSid, instanceName, sharedInstanceName, ReservedValue), + EventIds.SharingInstanceFailed, + instanceName); - Logger.SharedInstance(instanceName, ownerSid, sharedInstanceName); - } - finally - { - Marshal.FreeHGlobal(ptrSid); - } + Logger.SharedInstance(instanceName, ownerSid, sharedInstanceName); } + finally + { + Marshal.FreeHGlobal(ptrSid); + } + } - /// - /// Starts the specified instance of SQL Server LocalDB. - /// - /// The name of the LocalDB instance to start. - /// - /// The named pipe to use to connect to the LocalDB instance. - /// - /// - /// is . - /// - /// - /// SQL Server LocalDB is not installed on the local machine. - /// - /// - /// The method is called from a non-Windows operating system. - /// - /// - /// The SQL Server LocalDB instance specified by could not be started. - /// - public string StartInstance(string instanceName) + /// + /// Starts the specified instance of SQL Server LocalDB. + /// + /// The name of the LocalDB instance to start. + /// + /// The named pipe to use to connect to the LocalDB instance. + /// + /// + /// is . + /// + /// + /// SQL Server LocalDB is not installed on the local machine. + /// + /// + /// The method is called from a non-Windows operating system. + /// + /// + /// The SQL Server LocalDB instance specified by could not be started. + /// + public string StartInstance(string instanceName) + { + if (instanceName == null) { - if (instanceName == null) - { - throw new ArgumentNullException(nameof(instanceName)); - } + throw new ArgumentNullException(nameof(instanceName)); + } - Logger.StartingInstance(instanceName); + Logger.StartingInstance(instanceName); - int size = LocalDbInstanceApi.MaximumSqlConnectionStringBufferLength + 1; - var buffer = new StringBuilder(size); + int size = LocalDbInstanceApi.MaximumSqlConnectionStringBufferLength + 1; + var buffer = new StringBuilder(size); - InvokeThrowOnError( - () => _api.StartInstance(instanceName, ReservedValue, buffer, ref size), - EventIds.StartingInstanceFailed, - instanceName); + InvokeThrowOnError( + () => _api.StartInstance(instanceName, ReservedValue, buffer, ref size), + EventIds.StartingInstanceFailed, + instanceName); - string namedPipe = buffer.ToString(); + string namedPipe = buffer.ToString(); - Logger.StartedInstance(instanceName, namedPipe); + Logger.StartedInstance(instanceName, namedPipe); - return namedPipe; - } + return namedPipe; + } - /// - /// Enables tracing of native API calls for all the SQL Server - /// LocalDB instances owned by the current Windows user. - /// - /// - /// SQL Server LocalDB is not installed on the local machine. - /// - /// - /// The method is called from a non-Windows operating system. - /// - /// - /// Tracing could not be initialized. - /// - public void StartTracing() - { - Logger.StartingTracing(); + /// + /// Enables tracing of native API calls for all the SQL Server + /// LocalDB instances owned by the current Windows user. + /// + /// + /// SQL Server LocalDB is not installed on the local machine. + /// + /// + /// The method is called from a non-Windows operating system. + /// + /// + /// Tracing could not be initialized. + /// + public void StartTracing() + { + Logger.StartingTracing(); - InvokeThrowOnError(_api.StartTracing, EventIds.StartingTracingFailed); + InvokeThrowOnError(_api.StartTracing, EventIds.StartingTracingFailed); - Logger.StartedTracing(); - } + Logger.StartedTracing(); + } + + /// + /// Stops the specified instance of SQL Server LocalDB using + /// the timeout specified by . + /// + /// + /// The name of the LocalDB instance to stop. + /// + /// + /// is . + /// + /// + /// SQL Server LocalDB is not installed on the local machine. + /// + /// + /// The method is called from a non-Windows operating system. + /// + /// + /// The SQL Server LocalDB instance specified by could not be stopped. + /// + public void StopInstance(string instanceName) + { + StopInstance(instanceName, _stopTimeout); + } + + /// + /// Stops the specified instance of SQL Server LocalDB. + /// + /// + /// The name of the LocalDB instance to stop. + /// + /// + /// The optional amount of time to give the LocalDB instance to stop. + /// If no value is specified, the value of will + /// be used. If the value is , the method will + /// return immediately and not wait for the instance to stop. + /// + /// + /// is . + /// + /// + /// is less than . + /// + /// + /// SQL Server LocalDB is not installed on the local machine. + /// + /// + /// The method is called from a non-Windows operating system. + /// + /// + /// The SQL Server LocalDB instance specified by could not be stopped. + /// + /// + /// The parameter is rounded to the nearest second. + /// + public void StopInstance(string instanceName, TimeSpan? timeout) + { + StopInstance(instanceName, StopOptions, timeout); + } - /// - /// Stops the specified instance of SQL Server LocalDB using - /// the timeout specified by . - /// - /// - /// The name of the LocalDB instance to stop. - /// - /// - /// is . - /// - /// - /// SQL Server LocalDB is not installed on the local machine. - /// - /// - /// The method is called from a non-Windows operating system. - /// - /// - /// The SQL Server LocalDB instance specified by could not be stopped. - /// - public void StopInstance(string instanceName) + /// + /// Stops the specified instance of SQL Server LocalDB. + /// + /// + /// The name of the LocalDB instance to stop. + /// + /// + /// The options specifying the way to stop the instance. + /// + /// + /// The amount of time to give the LocalDB instance to stop. + /// If no value is specified, the value of will + /// be used. If the value is , the method will + /// return immediately and not wait for the instance to stop. + /// + /// + /// is . + /// + /// + /// is less than . + /// + /// + /// SQL Server LocalDB is not installed on the local machine. + /// + /// + /// The method is called from a non-Windows operating system. + /// + /// + /// The SQL Server LocalDB instance specified by could not be stopped. + /// + /// + /// The parameter is rounded to the nearest second. + /// + public void StopInstance(string instanceName, StopInstanceOptions options, TimeSpan? timeout) + { + if (instanceName == null) { - StopInstance(instanceName, _stopTimeout); + throw new ArgumentNullException(nameof(instanceName)); } - /// - /// Stops the specified instance of SQL Server LocalDB. - /// - /// - /// The name of the LocalDB instance to stop. - /// - /// - /// The optional amount of time to give the LocalDB instance to stop. - /// If no value is specified, the value of will - /// be used. If the value is , the method will - /// return immediately and not wait for the instance to stop. - /// - /// - /// is . - /// - /// - /// is less than . - /// - /// - /// SQL Server LocalDB is not installed on the local machine. - /// - /// - /// The method is called from a non-Windows operating system. - /// - /// - /// The SQL Server LocalDB instance specified by could not be stopped. - /// - /// - /// The parameter is rounded to the nearest second. - /// - public void StopInstance(string instanceName, TimeSpan? timeout) + TimeSpan theTimeout = timeout ?? StopTimeout; + + if (theTimeout < TimeSpan.Zero) { - StopInstance(instanceName, StopOptions, timeout); + string message = SRHelper.Format(SR.SqlLocalDbApi_TimeoutTooSmallFormat, nameof(timeout)); + throw new ArgumentOutOfRangeException(nameof(timeout), timeout, message); } - /// - /// Stops the specified instance of SQL Server LocalDB. - /// - /// - /// The name of the LocalDB instance to stop. - /// - /// - /// The options specifying the way to stop the instance. - /// - /// - /// The amount of time to give the LocalDB instance to stop. - /// If no value is specified, the value of will - /// be used. If the value is , the method will - /// return immediately and not wait for the instance to stop. - /// - /// - /// is . - /// - /// - /// is less than . - /// - /// - /// SQL Server LocalDB is not installed on the local machine. - /// - /// - /// The method is called from a non-Windows operating system. - /// - /// - /// The SQL Server LocalDB instance specified by could not be stopped. - /// - /// - /// The parameter is rounded to the nearest second. - /// - public void StopInstance(string instanceName, StopInstanceOptions options, TimeSpan? timeout) - { - if (instanceName == null) - { - throw new ArgumentNullException(nameof(instanceName)); - } + Logger.StoppingInstance(instanceName, theTimeout, options); + Stopwatch stopwatch = Stopwatch.StartNew(); - TimeSpan theTimeout = timeout ?? StopTimeout; + InvokeThrowOnError( + () => _api.StopInstance(instanceName, options, (int)theTimeout.TotalSeconds), + EventIds.StoppingInstanceFailed, + instanceName); - if (theTimeout < TimeSpan.Zero) - { - string message = SRHelper.Format(SR.SqlLocalDbApi_TimeoutTooSmallFormat, nameof(timeout)); - throw new ArgumentOutOfRangeException(nameof(timeout), timeout, message); - } + stopwatch.Stop(); - Logger.StoppingInstance(instanceName, theTimeout, options); - Stopwatch stopwatch = Stopwatch.StartNew(); + Logger.StoppedInstance(instanceName, stopwatch.Elapsed); + } - InvokeThrowOnError( - () => _api.StopInstance(instanceName, options, (int)theTimeout.TotalSeconds), - EventIds.StoppingInstanceFailed, - instanceName); + /// + /// Disables tracing of native API calls for all the SQL Server + /// LocalDB instances owned by the current Windows user. + /// + /// + /// SQL Server LocalDB is not installed on the local machine. + /// + /// + /// The method is called from a non-Windows operating system. + /// + /// + /// Tracing could not be disabled. + /// + public void StopTracing() + { + Logger.StoppingTracing(); - stopwatch.Stop(); + InvokeThrowOnError(_api.StopTracing, EventIds.StoppingTracingFailed); - Logger.StoppedInstance(instanceName, stopwatch.Elapsed); - } + Logger.StoppedTracing(); + } - /// - /// Disables tracing of native API calls for all the SQL Server - /// LocalDB instances owned by the current Windows user. - /// - /// - /// SQL Server LocalDB is not installed on the local machine. - /// - /// - /// The method is called from a non-Windows operating system. - /// - /// - /// Tracing could not be disabled. - /// - public void StopTracing() + /// + /// Stops the sharing of the specified SQL Server LocalDB instance. + /// + /// + /// The private name for the LocalDB instance to stop sharing. + /// + /// + /// is . + /// + /// + /// SQL Server LocalDB is not installed on the local machine. + /// + /// + /// The method is called from a non-Windows operating system. + /// + /// + /// The SQL Server LocalDB instance specified by could not be unshared. + /// + public void UnshareInstance(string instanceName) + { + if (instanceName == null) { - Logger.StoppingTracing(); - - InvokeThrowOnError(_api.StopTracing, EventIds.StoppingTracingFailed); - - Logger.StoppedTracing(); + throw new ArgumentNullException(nameof(instanceName)); } - /// - /// Stops the sharing of the specified SQL Server LocalDB instance. - /// - /// - /// The private name for the LocalDB instance to stop sharing. - /// - /// - /// is . - /// - /// - /// SQL Server LocalDB is not installed on the local machine. - /// - /// - /// The method is called from a non-Windows operating system. - /// - /// - /// The SQL Server LocalDB instance specified by could not be unshared. - /// - public void UnshareInstance(string instanceName) - { - if (instanceName == null) - { - throw new ArgumentNullException(nameof(instanceName)); - } + Logger.UnsharingInstance(instanceName); - Logger.UnsharingInstance(instanceName); + InvokeThrowOnError( + () => _api.UnshareInstance(instanceName, ReservedValue), + EventIds.UnsharingInstanceFailed, + instanceName); - InvokeThrowOnError( - () => _api.UnshareInstance(instanceName, ReservedValue), - EventIds.UnsharingInstanceFailed, - instanceName); - - Logger.UnsharedInstance(instanceName); - } + Logger.UnsharedInstance(instanceName); + } - /// - /// Throws an exception if the SQL LocalDB Instance API is not supported by the current platform. - /// - /// - /// The method is called from a non-Windows operating system. - /// - internal static void EnsurePlatformSupported() + /// + /// Throws an exception if the SQL LocalDB Instance API is not supported by the current platform. + /// + /// + /// The method is called from a non-Windows operating system. + /// + internal static void EnsurePlatformSupported() + { + if (!IsWindows) { - if (!IsWindows) - { - throw new PlatformNotSupportedException(SR.SqlLocalDbApi_PlatformNotSupported); - } + throw new PlatformNotSupportedException(SR.SqlLocalDbApi_PlatformNotSupported); } + } - /// - /// Returns whether the specified SQL LocalDB instance name is one of the default instance names. - /// - /// The instance name to test. - /// - /// if is one of the default SQL LocalDB - /// instance names; otherwise . - /// - internal static bool IsDefaultInstanceName(string instanceName) - { - return - string.Equals(instanceName, DefaultInstanceName2014AndLater, StringComparison.OrdinalIgnoreCase) || - string.Equals(instanceName, DefaultInstanceName2012, StringComparison.OrdinalIgnoreCase); - } + /// + /// Returns whether the specified SQL LocalDB instance name is one of the default instance names. + /// + /// The instance name to test. + /// + /// if is one of the default SQL LocalDB + /// instance names; otherwise . + /// + internal static bool IsDefaultInstanceName(string instanceName) + { + return + string.Equals(instanceName, DefaultInstanceName2014AndLater, StringComparison.OrdinalIgnoreCase) || + string.Equals(instanceName, DefaultInstanceName2012, StringComparison.OrdinalIgnoreCase); + } - /// - /// Deletes the specified SQL Server LocalDB instance. - /// - /// - /// The name of the LocalDB instance to delete. - /// - /// - /// Whether to throw an exception if the SQL LocalDB instance - /// specified by cannot be found. - /// - /// - /// Whether to delete the file(s) associated with the SQL LocalDB instance. - /// - /// - /// if the instance specified by - /// was successfully deleted; if - /// is and the instance did not exist. - /// - /// - /// is . - /// - /// - /// SQL Server LocalDB is not installed on the local machine. - /// - /// - /// The method is called from a non-Windows operating system. - /// - /// - /// The SQL Server LocalDB instance specified by could not be deleted. - /// - internal bool DeleteInstanceInternal(string instanceName, bool throwIfNotFound, bool deleteFiles = false) + /// + /// Deletes the specified SQL Server LocalDB instance. + /// + /// + /// The name of the LocalDB instance to delete. + /// + /// + /// Whether to throw an exception if the SQL LocalDB instance + /// specified by cannot be found. + /// + /// + /// Whether to delete the file(s) associated with the SQL LocalDB instance. + /// + /// + /// if the instance specified by + /// was successfully deleted; if + /// is and the instance did not exist. + /// + /// + /// is . + /// + /// + /// SQL Server LocalDB is not installed on the local machine. + /// + /// + /// The method is called from a non-Windows operating system. + /// + /// + /// The SQL Server LocalDB instance specified by could not be deleted. + /// + internal bool DeleteInstanceInternal(string instanceName, bool throwIfNotFound, bool deleteFiles = false) + { + if (instanceName == null) { - if (instanceName == null) - { - throw new ArgumentNullException(nameof(instanceName)); - } - - EnsurePlatformSupported(); - - Logger.DeletingInstance(instanceName); + throw new ArgumentNullException(nameof(instanceName)); + } - int hr = _api.DeleteInstance(instanceName, ReservedValue); + EnsurePlatformSupported(); - if (hr != 0) - { - if (!throwIfNotFound && hr == SqlLocalDbErrors.UnknownInstance) - { - Logger.DeletingInstanceFailedAsNotFound(instanceName); - return false; - } + Logger.DeletingInstance(instanceName); - throw GetLocalDbError(hr, EventIds.DeletingInstanceFailed, instanceName); - } + int hr = _api.DeleteInstance(instanceName, ReservedValue); - if (deleteFiles) + if (hr != 0) + { + if (!throwIfNotFound && hr == SqlLocalDbErrors.UnknownInstance) { - DeleteInstanceFiles(instanceName); + Logger.DeletingInstanceFailedAsNotFound(instanceName); + return false; } - Logger.DeletedInstance(instanceName); - return true; + throw GetLocalDbError(hr, EventIds.DeletingInstanceFailed, instanceName); } - /// - /// Deletes the file(s) from disk that are associated with the specified SQL LocalDB instance. - /// - /// The name of the SQL LocalDB instance to delete the file(s) for. - internal void DeleteInstanceFiles(string instanceName) + if (deleteFiles) { - Debug.Assert(instanceName != null, "instanceName cannot be null."); + DeleteInstanceFiles(instanceName); + } - // Sanitize the instance name's path to prevent directory traversal - string instanceNameSafe = Path.GetFullPath(instanceName); - instanceNameSafe = Path.GetFileName(instanceNameSafe); + Logger.DeletedInstance(instanceName); + return true; + } - string instancePath = Path.Combine(GetInstancesFolderPath(), instanceNameSafe); + /// + /// Deletes the file(s) from disk that are associated with the specified SQL LocalDB instance. + /// + /// The name of the SQL LocalDB instance to delete the file(s) for. + internal void DeleteInstanceFiles(string instanceName) + { + Debug.Assert(instanceName != null, "instanceName cannot be null."); - try - { - if (Directory.Exists(instancePath)) - { - Logger.DeletingInstanceFiles(instanceName!, instancePath); + // Sanitize the instance name's path to prevent directory traversal + string instanceNameSafe = Path.GetFullPath(instanceName); + instanceNameSafe = Path.GetFileName(instanceNameSafe); - Directory.Delete(instancePath, recursive: true); + string instancePath = Path.Combine(GetInstancesFolderPath(), instanceNameSafe); - Logger.DeletedInstanceFiles(instanceName!, instancePath); - } - } - catch (Exception ex) when (ex is ArgumentException || ex is IOException || ex is UnauthorizedAccessException) + try + { + if (Directory.Exists(instancePath)) { - Logger.DeletingInstanceFilesFailed(instanceName!, instancePath); + Logger.DeletingInstanceFiles(instanceName!, instancePath); + + Directory.Delete(instancePath, recursive: true); + + Logger.DeletedInstanceFiles(instanceName!, instancePath); } } - - /// - /// Returns an representing the specified LocalDB HRESULT. - /// - /// The HRESULT returned by the LocalDB API. - /// The trace event Id associated with the error. - /// The name of the instance that caused the error, if any. - /// - /// An representing . - /// - internal Exception GetLocalDbError(int hr, EventId eventId, string instanceName = "") + catch (Exception ex) when (ex is ArgumentException || ex is IOException || ex is UnauthorizedAccessException) { - string message; + Logger.DeletingInstanceFilesFailed(instanceName!, instancePath); + } + } - Logger.LogError(eventId, SR.SqlLocalDbApi_NativeResultFormat, hr.ToString("X", CultureInfo.InvariantCulture)); + /// + /// Returns an representing the specified LocalDB HRESULT. + /// + /// The HRESULT returned by the LocalDB API. + /// The trace event Id associated with the error. + /// The name of the instance that caused the error, if any. + /// + /// An representing . + /// + internal Exception GetLocalDbError(int hr, EventId eventId, string instanceName = "") + { + string message; - if (hr == SqlLocalDbErrors.NotInstalled) - { - Logger.NotInstalled(); - throw new InvalidOperationException(SRHelper.Format(SR.SqlLocalDbApi_NotInstalledFormat, Environment.MachineName)); - } + Logger.LogError(eventId, SR.SqlLocalDbApi_NativeResultFormat, hr.ToString("X", CultureInfo.InvariantCulture)); - int size = LocalDbInstanceApi.MaximumSqlConnectionStringBufferLength + 1; - var buffer = new StringBuilder(size); + if (hr == SqlLocalDbErrors.NotInstalled) + { + Logger.NotInstalled(); + throw new InvalidOperationException(SRHelper.Format(SR.SqlLocalDbApi_NotInstalledFormat, Environment.MachineName)); + } - // Get the description of the error from the LocalDB API. - int hr2 = _api.GetLocalDbError( - hr, - LanguageId, - buffer, - ref size); + int size = LocalDbInstanceApi.MaximumSqlConnectionStringBufferLength + 1; + var buffer = new StringBuilder(size); - if (hr2 == 0) - { - message = buffer.ToString(); - Logger.LogError(eventId, message); - } - else if (hr2 == SqlLocalDbErrors.UnknownLanguageId) - { - Logger.LogError( - eventId, - SR.SqlLocalDbApi_LogGenericFailureFormat, - hr2.ToString("X", CultureInfo.InvariantCulture)); - - // If the value of DefaultLanguageId was not understood by the API, - // then log an error informing the user. Do not throw an exception in - // this case as otherwise we will mask the original exception from the user. - Logger.InvalidLanguageId(LanguageId); - - // Use a generic message if getting the message from the API failed - message = SRHelper.Format(SR.SqlLocalDbApi_GenericFailureFormat, hr); - } - else - { - Logger.LogError( - eventId, - SR.SqlLocalDbApi_LogGenericFailureFormat, - hr2.ToString("X", CultureInfo.InvariantCulture)); + // Get the description of the error from the LocalDB API. + int hr2 = _api.GetLocalDbError( + hr, + LanguageId, + buffer, + ref size); - // Use a generic message if getting the message from the API failed. - // N.B. That if this occurs, then the original error is masked (although it is logged). - message = SRHelper.Format(SR.SqlLocalDbApi_GenericFailureFormat, hr2); + if (hr2 == 0) + { + message = buffer.ToString(); + Logger.LogError(eventId, message); + } + else if (hr2 == SqlLocalDbErrors.UnknownLanguageId) + { + Logger.LogError( + eventId, + SR.SqlLocalDbApi_LogGenericFailureFormat, + hr2.ToString("X", CultureInfo.InvariantCulture)); + + // If the value of DefaultLanguageId was not understood by the API, + // then log an error informing the user. Do not throw an exception in + // this case as otherwise we will mask the original exception from the user. + Logger.InvalidLanguageId(LanguageId); + + // Use a generic message if getting the message from the API failed + message = SRHelper.Format(SR.SqlLocalDbApi_GenericFailureFormat, hr); + } + else + { + Logger.LogError( + eventId, + SR.SqlLocalDbApi_LogGenericFailureFormat, + hr2.ToString("X", CultureInfo.InvariantCulture)); - return new SqlLocalDbException(message, hr2, instanceName); - } + // Use a generic message if getting the message from the API failed. + // N.B. That if this occurs, then the original error is masked (although it is logged). + message = SRHelper.Format(SR.SqlLocalDbApi_GenericFailureFormat, hr2); - return new SqlLocalDbException(message, hr, instanceName); + return new SqlLocalDbException(message, hr2, instanceName); } - /// - /// Converts a representation of a SID to an array of bytes. - /// - /// The SID to convert to a byte array. - /// - /// An of containing a representation of . - /// + return new SqlLocalDbException(message, hr, instanceName); + } + + /// + /// Converts a representation of a SID to an array of bytes. + /// + /// The SID to convert to a byte array. + /// + /// An of containing a representation of . + /// #if NET5_0_OR_GREATER - [System.Runtime.Versioning.SupportedOSPlatform("windows")] + [System.Runtime.Versioning.SupportedOSPlatform("windows")] #endif - private static byte[] GetOwnerSidAsByteArray(string ownerSid) + private static byte[] GetOwnerSidAsByteArray(string ownerSid) + { + // Get the binary version of the SID from its string + SecurityIdentifier sid = new SecurityIdentifier(ownerSid); + byte[] binaryForm = new byte[SecurityIdentifier.MaxBinaryLength]; + sid.GetBinaryForm(binaryForm, 0); + return binaryForm; + } + + /// + /// Convenience method to marshal string arrays from unmanaged memory. + /// + /// A pointer to an unmanaged block of memory. + /// The length of each string in the array. + /// The number of elements in the array. + /// + /// An of strings read from . + /// + private static string[] MarshalStringArray(IntPtr ptr, int length, int count) + { + Debug.Assert(ptr != IntPtr.Zero, "The unmanaged memory pointer is invalid."); + Debug.Assert(length > 0, "The length of the elements cannot be less than one."); + Debug.Assert(count > -1, "The number of elements in the array cannot be negative."); + + string[] result = new string[count]; + + for (int i = 0; i < result.Length; i++) { - // Get the binary version of the SID from its string - SecurityIdentifier sid = new SecurityIdentifier(ownerSid); - byte[] binaryForm = new byte[SecurityIdentifier.MaxBinaryLength]; - sid.GetBinaryForm(binaryForm, 0); - return binaryForm; + // Determine the offset of the element, and get the string from the array + IntPtr offset = new IntPtr(ptr.ToInt64() + (length * i)); + result[i] = Marshal.PtrToStringAuto(offset) !; } - /// - /// Convenience method to marshal string arrays from unmanaged memory. - /// - /// A pointer to an unmanaged block of memory. - /// The length of each string in the array. - /// The number of elements in the array. - /// - /// An of strings read from . - /// - private static string[] MarshalStringArray(IntPtr ptr, int length, int count) - { - Debug.Assert(ptr != IntPtr.Zero, "The unmanaged memory pointer is invalid."); - Debug.Assert(length > 0, "The length of the elements cannot be less than one."); - Debug.Assert(count > -1, "The number of elements in the array cannot be negative."); + return result; + } - string[] result = new string[count]; + /// + /// Convenience method to marshal structures from unmanaged memory. + /// + /// The type of structure to marshal from unmanaged memory. + /// A pointer to an unmanaged block of memory. + /// + /// The instance of read from . + /// + private static T MarshalStruct(IntPtr ptr) + where T : struct + { + return (T)Marshal.PtrToStructure(ptr, typeof(T)) !; + } - for (int i = 0; i < result.Length; i++) - { - // Determine the offset of the element, and get the string from the array - IntPtr offset = new IntPtr(ptr.ToInt64() + (length * i)); - result[i] = Marshal.PtrToStringAuto(offset) !; - } + /// + /// Gets the available versions of SQL LocalDB installed on the local machine. + /// + /// + /// An of containing the available versions. + /// + /// + /// SQL Server LocalDB is not installed on the local machine. + /// + /// + /// The method is called from a non-Windows operating system. + /// + /// + /// The installed LocalDB versions could not be enumerated. + /// + private string[] GetLocalDbVersions() + { + EnsurePlatformSupported(); - return result; - } + string[] versions; - /// - /// Convenience method to marshal structures from unmanaged memory. - /// - /// The type of structure to marshal from unmanaged memory. - /// A pointer to an unmanaged block of memory. - /// - /// The instance of read from . - /// - private static T MarshalStruct(IntPtr ptr) - where T : struct + try { - return (T)Marshal.PtrToStructure(ptr, typeof(T)) !; - } + Logger.GettingVersions(); - /// - /// Gets the available versions of SQL LocalDB installed on the local machine. - /// - /// - /// An of containing the available versions. - /// - /// - /// SQL Server LocalDB is not installed on the local machine. - /// - /// - /// The method is called from a non-Windows operating system. - /// - /// - /// The installed LocalDB versions could not be enumerated. - /// - private string[] GetLocalDbVersions() - { - EnsurePlatformSupported(); + // Query the LocalDB API to get the number of instances + int count = 0; + int hr = _api.GetVersions(IntPtr.Zero, ref count); - string[] versions; + if (hr != 0 && + hr != SqlLocalDbErrors.InsufficientBuffer) + { + throw GetLocalDbError(hr, EventIds.GettingVersionsFailed); + } + + // Allocate enough memory to receive the version name array + int versionLength = MaxVersionLength; + IntPtr ptrVersions = Marshal.AllocHGlobal(versionLength * count); try { - Logger.GettingVersions(); - - // Query the LocalDB API to get the number of instances - int count = 0; - int hr = _api.GetVersions(IntPtr.Zero, ref count); + hr = _api.GetVersions(ptrVersions, ref count); - if (hr != 0 && - hr != SqlLocalDbErrors.InsufficientBuffer) + if (hr != 0) { throw GetLocalDbError(hr, EventIds.GettingVersionsFailed); } - // Allocate enough memory to receive the version name array - int versionLength = MaxVersionLength; - IntPtr ptrVersions = Marshal.AllocHGlobal(versionLength * count); - - try - { - hr = _api.GetVersions(ptrVersions, ref count); - - if (hr != 0) - { - throw GetLocalDbError(hr, EventIds.GettingVersionsFailed); - } - - // Read the version strings back from unmanaged memory - versions = MarshalStringArray(ptrVersions, versionLength, count); - } - finally - { - Marshal.FreeHGlobal(ptrVersions); - } + // Read the version strings back from unmanaged memory + versions = MarshalStringArray(ptrVersions, versionLength, count); } - catch (SqlLocalDbException ex) + finally { - throw new SqlLocalDbException( - SR.SqlLocalDbApi_VersionEnumerationFailed, - ex.ErrorCode, - ex.InstanceName, - ex); + Marshal.FreeHGlobal(ptrVersions); } + } + catch (SqlLocalDbException ex) + { + throw new SqlLocalDbException( + SR.SqlLocalDbApi_VersionEnumerationFailed, + ex.ErrorCode, + ex.InstanceName, + ex); + } - Logger.GotVersions(versions.Length); + Logger.GotVersions(versions.Length); - return versions; - } + return versions; + } - /// - /// Invokes the specified delegate, throwing an exception if the delegate does not return zero. - /// - /// A delegate to a method to invoke. - /// The trace event Id if a non-zero value is returned. - /// The name of the instance that caused the error, if any. - /// - /// The method is called from a non-Windows operating system. - /// - private void InvokeThrowOnError(Func func, EventId eventId, string instanceName = "") - { - EnsurePlatformSupported(); + /// + /// Invokes the specified delegate, throwing an exception if the delegate does not return zero. + /// + /// A delegate to a method to invoke. + /// The trace event Id if a non-zero value is returned. + /// The name of the instance that caused the error, if any. + /// + /// The method is called from a non-Windows operating system. + /// + private void InvokeThrowOnError(Func func, EventId eventId, string instanceName = "") + { + EnsurePlatformSupported(); - int hr = func(); + int hr = func(); - if (hr != 0) - { - throw GetLocalDbError(hr, eventId, instanceName); - } + if (hr != 0) + { + throw GetLocalDbError(hr, eventId, instanceName); } + } - /// - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// - /// - /// to release both managed and unmanaged resources; - /// to release only unmanaged resources. - /// - private void Dispose(bool disposing) + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + /// + /// to release both managed and unmanaged resources; + /// to release only unmanaged resources. + /// + private void Dispose(bool disposing) + { + if (!_disposed) { - if (!_disposed) + if (disposing) { - if (disposing) - { - _api.Dispose(); - } - - _disposed = true; + _api.Dispose(); } + + _disposed = true; } } } diff --git a/src/SqlLocalDb/SqlLocalDbErrors.cs b/src/SqlLocalDb/SqlLocalDbErrors.cs index bd01590b..570a9a2a 100644 --- a/src/SqlLocalDb/SqlLocalDbErrors.cs +++ b/src/SqlLocalDb/SqlLocalDbErrors.cs @@ -3,443 +3,442 @@ using System.Diagnostics.CodeAnalysis; -namespace MartinCostello.SqlLocalDb +namespace MartinCostello.SqlLocalDb; + +/// +/// A class containing SQL Server LocalDB errors. This class cannot be inherited. +/// +public static class SqlLocalDbErrors { /// - /// A class containing SQL Server LocalDB errors. This class cannot be inherited. - /// - public static class SqlLocalDbErrors - { - /// - /// Cannot create folder for the LocalDB instance at: %LOCALAPPDATA%\Microsoft\Microsoft SQL Server Local DB\Instances\<instance name>. - /// - /// - /// Maps to the LOCALDB_ERROR_CANNOT_CREATE_INSTANCE_FOLDER error. - /// - public static readonly int CannotCreateInstanceFolder = unchecked((int)0x89c50100); - - /// - /// The parameter for the LocalDB Instance API method is incorrect. - /// - /// - /// Maps to the LOCALDB_ERROR_INVALID_PARAMETER error. - /// - public static readonly int InvalidParameter = unchecked((int)0x89c50101); - - /// - /// Unable to create the LocalDB instance with specified version. - /// An instance with the same name already exists, but it has lower - /// version than the specified version. - /// - /// - /// Maps to the LOCALDB_ERROR_INSTANCE_EXISTS_WITH_LOWER_VERSION error. - /// - public static readonly int InstanceExistsWithLowerVersion = unchecked((int)0x89c50102); - - /// - /// Cannot access the user profile folder for local application data (%LOCALAPPDATA%). - /// - /// - /// Maps to the LOCALDB_ERROR_CANNOT_GET_USER_PROFILE_FOLDER error. - /// - public static readonly int CannotGetUserProfileFolder = unchecked((int)0x89c50103); - - /// - /// The full path length of the LocalDB instance folder is longer than - /// MAX_PATH. The instance must be stored in folder: %LOCALAPPDATA%\Microsoft\Microsoft SQL Server Local DB\Instances\<instance name>. - /// - /// - /// Maps to the LOCALDB_ERROR_INSTANCE_FOLDER_PATH_TOO_LONG error. - /// - [SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "long", Justification = "Usage is safe.")] - public static readonly int InstanceFolderPathTooLong = unchecked((int)0x89c50104); - - /// - /// Cannot access LocalDB instance folder: %LOCALAPPDATA%\Microsoft\Microsoft SQL Server Local DB\Instances\<instance name>. - /// - /// - /// Maps to the LOCALDB_ERROR_CANNOT_ACCESS_INSTANCE_FOLDER error. - /// - public static readonly int CannotAccessInstanceFolder = unchecked((int)0x89c50105); - - /// - /// Unexpected error occurred while trying to access the LocalDB instance - /// registry configuration. See the Windows Application event log for error details. - /// - /// - /// Maps to the LOCALDB_ERROR_CANNOT_ACCESS_INSTANCE_REGISTRY error. - /// - public static readonly int CannotAccessInstanceRegistry = unchecked((int)0x89c50106); - - /// - /// The specified LocalDB instance does not exist. - /// - /// - /// Maps to the LOCALDB_ERROR_UNKNOWN_INSTANCE error. - /// - public static readonly int UnknownInstance = unchecked((int)0x89c50107); - - /// - /// Unexpected error occurred inside a LocalDB instance API method call. - /// See the Windows Application event log for error details. - /// - /// - /// Maps to the LOCALDB_ERROR_INTERNAL_ERROR error. - /// - public static readonly int InternalError = unchecked((int)0x89c50108); - - /// - /// Unexpected error occurred while trying to modify the registry - /// configuration for the LocalDB instance. See the Windows Application - /// event log for error details. - /// - /// - /// Maps to the LOCALDB_ERROR_CANNOT_MODIFY_INSTANCE_REGISTRY error. - /// - public static readonly int CannotModifyInstanceRegistry = unchecked((int)0x89c50109); - - /// - /// Error occurred during LocalDB instance startup: SQL Server process failed to start. - /// - /// - /// Maps to the LOCALDB_ERROR_SQL_SERVER_STARTUP_FAILED error. - /// - public static readonly int ServerStartupFailed = unchecked((int)0x89c5010a); - - /// - /// LocalDB instance is corrupted. See the Windows Application event log for error details. - /// - /// - /// Maps to the LOCALDB_ERROR_INSTANCE_CONFIGURATION_CORRUPT error. - /// - public static readonly int InstanceConfigurationCorrupt = unchecked((int)0x89c5010b); - - /// - /// Error occurred during LocalDB instance startup: unable to create the SQL Server process. - /// - /// - /// Maps to the LOCALDB_ERROR_CANNOT_CREATE_SQL_PROCESS error. - /// - public static readonly int CannotCreateSqlProcess = unchecked((int)0x89c5010c); - - /// - /// The specified LocalDB version is not available on this computer. - /// - /// - /// Maps to the LOCALDB_ERROR_UNKNOWN_VERSION error. - /// - public static readonly int UnknownVersion = unchecked((int)0x89c5010d); - - /// - /// Error getting the localized error message. - /// - /// - /// Maps to the LOCALDB_ERROR_UNKNOWN_LANGUAGE_ID error. - /// - public static readonly int UnknownLanguageId = unchecked((int)0x89c5010e); - - /// - /// Stop operation for LocalDB instance failed to complete within the specified time. - /// - /// - /// Maps to the LOCALDB_ERROR_INSTANCE_STOP_FAILED error. - /// - public static readonly int InstanceStopFailed = unchecked((int)0x89c5010f); - - /// - /// Error getting the localized error message. The specified error code is unknown. - /// - /// - /// Maps to the LOCALDB_ERROR_UNKNOWN_ERROR_CODE error. - /// - public static readonly int UnknownErrorCode = unchecked((int)0x89c50110); - - /// - /// The LocalDB version available on this workstation is lower than - /// the requested LocalDB version. - /// - /// - /// Maps to the LOCALDB_ERROR_VERSION_REQUESTED_NOT_INSTALLED error. - /// - public static readonly int VersionNotInstalled = unchecked((int)0x89c50111); - - /// - /// Requested operation on LocalDB instance cannot be performed because - /// specified instance is currently in use. Stop the instance and try again. - /// - /// - /// Maps to the LOCALDB_ERROR_INSTANCE_BUSY error. - /// - public static readonly int InstanceBusy = unchecked((int)0x89c50112); - - /// - /// Default LocalDB instances cannot be created, stopped or deleted manually. - /// - /// - /// Maps to the LOCALDB_ERROR_INVALID_OPERATION error. - /// - public static readonly int InvalidOperation = unchecked((int)0x89c50113); - - /// - /// The buffer passed to the LocalDB instance API method has insufficient size. - /// - /// - /// Maps to the LOCALDB_ERROR_INSUFFICIENT_BUFFER error. - /// - public static readonly int InsufficientBuffer = unchecked((int)0x89c50114); - - /// - /// Timeout occurred inside the LocalDB instance API method. - /// - /// - /// Maps to the LOCALDB_ERROR_WAIT_TIMEOUT error. - /// - public static readonly int WaitTimeout = unchecked((int)0x89c50115); - - /// - /// SQL Server LocalDB is not installed. - /// - /// - /// Maps to the LOCALDB_ERROR_NOT_INSTALLED error. - /// - public static readonly int NotInstalled = unchecked((int)0x89c50116); - - /// - /// Failed to start XEvent engine within the LocalDB Instance API. - /// - /// - /// Maps to the LOCALDB_ERROR_XEVENT_FAILED error. - /// - public static readonly int XEventFailed = unchecked((int)0x89c50117); - - /// - /// Cannot create an automatic instance. See the Windows Application event log for error details. - /// - /// - /// Maps to the LOCALDB_ERROR_AUTO_INSTANCE_CREATE_FAILED error. - /// - public static readonly int AutoInstanceCreateFailed = unchecked((int)0x89c50118); - - /// - /// Cannot create a shared instance. The specified shared instance name is already in use. - /// - /// - /// Maps to the LOCALDB_ERROR_SHARED_NAME_TAKEN error. - /// - public static readonly int SharedNameTaken = unchecked((int)0x89c50119); - - /// - /// API caller is not LocalDB instance owner. - /// - /// - /// Maps to the LOCALDB_ERROR_CALLER_IS_NOT_OWNER error. - /// - public static readonly int CallerIsNotOwner = unchecked((int)0x89c5011a); - - /// - /// Specified LocalDB instance name is invalid. - /// - /// - /// Maps to the LOCALDB_ERROR_INVALID_INSTANCE_NAME error. - /// - public static readonly int InvalidInstanceName = unchecked((int)0x89c5011b); - - /// - /// The specified LocalDB instance is already shared with different shared name. - /// - /// - /// Maps to the LOCALDB_ERROR_INSTANCE_ALREADY_SHARED error. - /// - public static readonly int InstanceAlreadyShared = unchecked((int)0x89c5011c); - - /// - /// The specified LocalDB instance is not shared. - /// - /// - /// Maps to the LOCALDB_ERROR_INSTANCE_NOT_SHARED error. - /// - public static readonly int InstanceNotShared = unchecked((int)0x89c5011d); - - /// - /// Administrator privileges are required in order to execute this operation. - /// - /// - /// Maps to the LOCALDB_ERROR_ADMIN_RIGHTS_REQUIRED error. - /// - public static readonly int AdminRightsRequired = unchecked((int)0x89c5011e); - - /// - /// Unable to share a LocalDB instance - maximum number of shared LocalDB instances reached. - /// - /// - /// Maps to the LOCALDB_ERROR_TOO_MANY_SHARED_INSTANCES error. - /// - public static readonly int TooManySharedInstances = unchecked((int)0x89c5011f); - - /// - /// The "Parent Instance" registry value is missing in the LocalDB instance registry key. - /// - /// - /// Maps to the LOCALDB_ERROR_CANNOT_GET_LOCAL_APP_DATA_PATH error. - /// - public static readonly int CannotGetLocalAppDataPath = unchecked((int)0x89c50120); - - /// - /// Cannot load resources for this DLL. Resources for this DLL should - /// be stored in a subfolder Resources, with the same file name as this DLL - /// and the extension ".RLL". - /// - /// - /// Maps to the LOCALDB_ERROR_CANNOT_LOAD_RESOURCES error. - /// - public static readonly int CannotLoadResources = unchecked((int)0x89c50121); - - /// - /// The "DataDirectory" registry value is missing in the LocalDB instance registry key. - /// - /// - /// Maps to the LOCALDB_EDETAIL_DATADIRECTORY_IS_MISSING error. - /// - public static readonly int DataDirectoryMissing = unchecked((int)0x89c50200); - - /// - /// Cannot access LocalDB instance folder. - /// - /// - /// Maps to the LOCALDB_EDETAIL_CANNOT_ACCESS_INSTANCE_FOLDER error. - /// - public static readonly int CannotAccessInstanceFolderDetail = unchecked((int)0x89c50201); - - /// - /// The "DataDirectory" registry value is too long in the LocalDB instance registry key. - /// - /// - /// Maps to the LOCALDB_EDETAIL_DATADIRECTORY_IS_TOO_LONG error. - /// - [SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "long", Justification = "Usage is safe.")] - public static readonly int DataDirectoryIsTooLong = unchecked((int)0x89c50202); - - /// - /// The "Parent Instance" registry value is missing in the LocalDB instance registry key. - /// - /// - /// Maps to the LOCALDB_EDETAIL_PARENT_INSTANCE_IS_MISSING error. - /// - public static readonly int ParentInstanceIsMissing = unchecked((int)0x89c50203); - - /// - /// The "Parent Instance" registry value is too long in the LocalDB instance registry key. - /// - /// - /// Maps to the LOCALDB_EDETAIL_PARENT_INSTANCE_IS_TOO_LONG error. - /// - [SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "long", Justification = "Usage is safe.")] - public static readonly int ParentInstanceIsTooLong = unchecked((int)0x89c50204); - - /// - /// Data directory for LocalDB instance is invalid. - /// - /// - /// Maps to the LOCALDB_EDETAIL_DATA_DIRECTORY_INVALID error. - /// - public static readonly int DataDirectoryInvalid = unchecked((int)0x89c50205); - - /// - /// LocalDB instance API: XEvent engine assert. - /// - /// - /// Maps to the LOCALDB_EDETAIL_XEVENT_ASSERT error. - /// - public static readonly int XEventAssert = unchecked((int)0x89c50206); - - /// - /// LocalDB instance API: XEvent error. - /// - /// - /// Maps to the LOCALDB_EDETAIL_XEVENT_ERROR error. - /// - public static readonly int XEventError = unchecked((int)0x89c50207); - - /// - /// LocalDB installation is corrupted. Reinstall the LocalDB. - /// - /// - /// Maps to the LOCALDB_EDETAIL_INSTALLATION_CORRUPTED error. - /// - public static readonly int InstallationCorrupted = unchecked((int)0x89c50208); - - /// - /// LocalDB XEvent error: cannot determine %ProgramFiles% folder location. - /// - /// - /// Maps to the LOCALDB_EDETAIL_CANNOT_GET_PROGRAM_FILES_LOCATION error. - /// - public static readonly int CannotGetProgramFilesLocation = unchecked((int)0x89c50209); - - /// - /// LocalDB XEvent error: Cannot initialize XEvent engine. - /// - /// - /// Maps to the LOCALDB_EDETAIL_XEVENT_CANNOT_INITIALIZE error. - /// - public static readonly int CannotInitializeXEvent = unchecked((int)0x89c5020a); - - /// - /// LocalDB XEvent error: Cannot find XEvents configuration file. - /// - /// - /// Maps to the LOCALDB_EDETAIL_XEVENT_CANNOT_FIND_CONF_FILE error. - /// - public static readonly int CannotFindXEventConfigFile = unchecked((int)0x89c5020b); - - /// - /// LocalDB XEvent error: Cannot configure XEvents engine with the configuration file. - /// - /// - /// Maps to the LOCALDB_EDETAIL_XEVENT_CANNOT_CONFIGURE error. - /// - public static readonly int CannotConfigureXEvent = unchecked((int)0x89c5020c); - - /// - /// LocalDB XEvent error: XEvents engine configuration file too long. - /// - /// - /// Maps to the LOCALDB_EDETAIL_XEVENT_CONF_FILE_NAME_TOO_LONG error. - /// - [SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "long", Justification = "Usage is safe.")] - public static readonly int XEventConfigFileTooLong = unchecked((int)0x89c5020d); - - /// - /// CoInitializeEx API failed. - /// - /// - /// Maps to the LOCALDB_EDETAIL_COINITIALIZEEX_FAILED error. - /// - [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Co", Justification = "Is part of a function name.")] - public static readonly int CoInitializeExFailed = unchecked((int)0x89c5020e); - - /// - /// LocalDB parent instance version is invalid. - /// - /// - /// Maps to the LOCALDB_EDETAIL_PARENT_INSTANCE_VERSION_INVALID error. - /// - public static readonly int ParentInstanceVersionInvalid = unchecked((int)0x89c5020f); - - /// - /// A Windows API call returned an error. - /// - /// - /// Maps to the LOCALDB_EDETAIL_WINAPI_ERROR error. - /// - public static readonly int WindowsApiError = unchecked((int)0x89c50210); - - /// - /// Unexpected result. - /// - /// - /// Maps to the LOCALDB_EDETAIL_UNEXPECTED_RESULT error. - /// - public static readonly int UnexpectedResult = unchecked((int)0x89c50211); - } + /// Cannot create folder for the LocalDB instance at: %LOCALAPPDATA%\Microsoft\Microsoft SQL Server Local DB\Instances\<instance name>. + /// + /// + /// Maps to the LOCALDB_ERROR_CANNOT_CREATE_INSTANCE_FOLDER error. + /// + public static readonly int CannotCreateInstanceFolder = unchecked((int)0x89c50100); + + /// + /// The parameter for the LocalDB Instance API method is incorrect. + /// + /// + /// Maps to the LOCALDB_ERROR_INVALID_PARAMETER error. + /// + public static readonly int InvalidParameter = unchecked((int)0x89c50101); + + /// + /// Unable to create the LocalDB instance with specified version. + /// An instance with the same name already exists, but it has lower + /// version than the specified version. + /// + /// + /// Maps to the LOCALDB_ERROR_INSTANCE_EXISTS_WITH_LOWER_VERSION error. + /// + public static readonly int InstanceExistsWithLowerVersion = unchecked((int)0x89c50102); + + /// + /// Cannot access the user profile folder for local application data (%LOCALAPPDATA%). + /// + /// + /// Maps to the LOCALDB_ERROR_CANNOT_GET_USER_PROFILE_FOLDER error. + /// + public static readonly int CannotGetUserProfileFolder = unchecked((int)0x89c50103); + + /// + /// The full path length of the LocalDB instance folder is longer than + /// MAX_PATH. The instance must be stored in folder: %LOCALAPPDATA%\Microsoft\Microsoft SQL Server Local DB\Instances\<instance name>. + /// + /// + /// Maps to the LOCALDB_ERROR_INSTANCE_FOLDER_PATH_TOO_LONG error. + /// + [SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "long", Justification = "Usage is safe.")] + public static readonly int InstanceFolderPathTooLong = unchecked((int)0x89c50104); + + /// + /// Cannot access LocalDB instance folder: %LOCALAPPDATA%\Microsoft\Microsoft SQL Server Local DB\Instances\<instance name>. + /// + /// + /// Maps to the LOCALDB_ERROR_CANNOT_ACCESS_INSTANCE_FOLDER error. + /// + public static readonly int CannotAccessInstanceFolder = unchecked((int)0x89c50105); + + /// + /// Unexpected error occurred while trying to access the LocalDB instance + /// registry configuration. See the Windows Application event log for error details. + /// + /// + /// Maps to the LOCALDB_ERROR_CANNOT_ACCESS_INSTANCE_REGISTRY error. + /// + public static readonly int CannotAccessInstanceRegistry = unchecked((int)0x89c50106); + + /// + /// The specified LocalDB instance does not exist. + /// + /// + /// Maps to the LOCALDB_ERROR_UNKNOWN_INSTANCE error. + /// + public static readonly int UnknownInstance = unchecked((int)0x89c50107); + + /// + /// Unexpected error occurred inside a LocalDB instance API method call. + /// See the Windows Application event log for error details. + /// + /// + /// Maps to the LOCALDB_ERROR_INTERNAL_ERROR error. + /// + public static readonly int InternalError = unchecked((int)0x89c50108); + + /// + /// Unexpected error occurred while trying to modify the registry + /// configuration for the LocalDB instance. See the Windows Application + /// event log for error details. + /// + /// + /// Maps to the LOCALDB_ERROR_CANNOT_MODIFY_INSTANCE_REGISTRY error. + /// + public static readonly int CannotModifyInstanceRegistry = unchecked((int)0x89c50109); + + /// + /// Error occurred during LocalDB instance startup: SQL Server process failed to start. + /// + /// + /// Maps to the LOCALDB_ERROR_SQL_SERVER_STARTUP_FAILED error. + /// + public static readonly int ServerStartupFailed = unchecked((int)0x89c5010a); + + /// + /// LocalDB instance is corrupted. See the Windows Application event log for error details. + /// + /// + /// Maps to the LOCALDB_ERROR_INSTANCE_CONFIGURATION_CORRUPT error. + /// + public static readonly int InstanceConfigurationCorrupt = unchecked((int)0x89c5010b); + + /// + /// Error occurred during LocalDB instance startup: unable to create the SQL Server process. + /// + /// + /// Maps to the LOCALDB_ERROR_CANNOT_CREATE_SQL_PROCESS error. + /// + public static readonly int CannotCreateSqlProcess = unchecked((int)0x89c5010c); + + /// + /// The specified LocalDB version is not available on this computer. + /// + /// + /// Maps to the LOCALDB_ERROR_UNKNOWN_VERSION error. + /// + public static readonly int UnknownVersion = unchecked((int)0x89c5010d); + + /// + /// Error getting the localized error message. + /// + /// + /// Maps to the LOCALDB_ERROR_UNKNOWN_LANGUAGE_ID error. + /// + public static readonly int UnknownLanguageId = unchecked((int)0x89c5010e); + + /// + /// Stop operation for LocalDB instance failed to complete within the specified time. + /// + /// + /// Maps to the LOCALDB_ERROR_INSTANCE_STOP_FAILED error. + /// + public static readonly int InstanceStopFailed = unchecked((int)0x89c5010f); + + /// + /// Error getting the localized error message. The specified error code is unknown. + /// + /// + /// Maps to the LOCALDB_ERROR_UNKNOWN_ERROR_CODE error. + /// + public static readonly int UnknownErrorCode = unchecked((int)0x89c50110); + + /// + /// The LocalDB version available on this workstation is lower than + /// the requested LocalDB version. + /// + /// + /// Maps to the LOCALDB_ERROR_VERSION_REQUESTED_NOT_INSTALLED error. + /// + public static readonly int VersionNotInstalled = unchecked((int)0x89c50111); + + /// + /// Requested operation on LocalDB instance cannot be performed because + /// specified instance is currently in use. Stop the instance and try again. + /// + /// + /// Maps to the LOCALDB_ERROR_INSTANCE_BUSY error. + /// + public static readonly int InstanceBusy = unchecked((int)0x89c50112); + + /// + /// Default LocalDB instances cannot be created, stopped or deleted manually. + /// + /// + /// Maps to the LOCALDB_ERROR_INVALID_OPERATION error. + /// + public static readonly int InvalidOperation = unchecked((int)0x89c50113); + + /// + /// The buffer passed to the LocalDB instance API method has insufficient size. + /// + /// + /// Maps to the LOCALDB_ERROR_INSUFFICIENT_BUFFER error. + /// + public static readonly int InsufficientBuffer = unchecked((int)0x89c50114); + + /// + /// Timeout occurred inside the LocalDB instance API method. + /// + /// + /// Maps to the LOCALDB_ERROR_WAIT_TIMEOUT error. + /// + public static readonly int WaitTimeout = unchecked((int)0x89c50115); + + /// + /// SQL Server LocalDB is not installed. + /// + /// + /// Maps to the LOCALDB_ERROR_NOT_INSTALLED error. + /// + public static readonly int NotInstalled = unchecked((int)0x89c50116); + + /// + /// Failed to start XEvent engine within the LocalDB Instance API. + /// + /// + /// Maps to the LOCALDB_ERROR_XEVENT_FAILED error. + /// + public static readonly int XEventFailed = unchecked((int)0x89c50117); + + /// + /// Cannot create an automatic instance. See the Windows Application event log for error details. + /// + /// + /// Maps to the LOCALDB_ERROR_AUTO_INSTANCE_CREATE_FAILED error. + /// + public static readonly int AutoInstanceCreateFailed = unchecked((int)0x89c50118); + + /// + /// Cannot create a shared instance. The specified shared instance name is already in use. + /// + /// + /// Maps to the LOCALDB_ERROR_SHARED_NAME_TAKEN error. + /// + public static readonly int SharedNameTaken = unchecked((int)0x89c50119); + + /// + /// API caller is not LocalDB instance owner. + /// + /// + /// Maps to the LOCALDB_ERROR_CALLER_IS_NOT_OWNER error. + /// + public static readonly int CallerIsNotOwner = unchecked((int)0x89c5011a); + + /// + /// Specified LocalDB instance name is invalid. + /// + /// + /// Maps to the LOCALDB_ERROR_INVALID_INSTANCE_NAME error. + /// + public static readonly int InvalidInstanceName = unchecked((int)0x89c5011b); + + /// + /// The specified LocalDB instance is already shared with different shared name. + /// + /// + /// Maps to the LOCALDB_ERROR_INSTANCE_ALREADY_SHARED error. + /// + public static readonly int InstanceAlreadyShared = unchecked((int)0x89c5011c); + + /// + /// The specified LocalDB instance is not shared. + /// + /// + /// Maps to the LOCALDB_ERROR_INSTANCE_NOT_SHARED error. + /// + public static readonly int InstanceNotShared = unchecked((int)0x89c5011d); + + /// + /// Administrator privileges are required in order to execute this operation. + /// + /// + /// Maps to the LOCALDB_ERROR_ADMIN_RIGHTS_REQUIRED error. + /// + public static readonly int AdminRightsRequired = unchecked((int)0x89c5011e); + + /// + /// Unable to share a LocalDB instance - maximum number of shared LocalDB instances reached. + /// + /// + /// Maps to the LOCALDB_ERROR_TOO_MANY_SHARED_INSTANCES error. + /// + public static readonly int TooManySharedInstances = unchecked((int)0x89c5011f); + + /// + /// The "Parent Instance" registry value is missing in the LocalDB instance registry key. + /// + /// + /// Maps to the LOCALDB_ERROR_CANNOT_GET_LOCAL_APP_DATA_PATH error. + /// + public static readonly int CannotGetLocalAppDataPath = unchecked((int)0x89c50120); + + /// + /// Cannot load resources for this DLL. Resources for this DLL should + /// be stored in a subfolder Resources, with the same file name as this DLL + /// and the extension ".RLL". + /// + /// + /// Maps to the LOCALDB_ERROR_CANNOT_LOAD_RESOURCES error. + /// + public static readonly int CannotLoadResources = unchecked((int)0x89c50121); + + /// + /// The "DataDirectory" registry value is missing in the LocalDB instance registry key. + /// + /// + /// Maps to the LOCALDB_EDETAIL_DATADIRECTORY_IS_MISSING error. + /// + public static readonly int DataDirectoryMissing = unchecked((int)0x89c50200); + + /// + /// Cannot access LocalDB instance folder. + /// + /// + /// Maps to the LOCALDB_EDETAIL_CANNOT_ACCESS_INSTANCE_FOLDER error. + /// + public static readonly int CannotAccessInstanceFolderDetail = unchecked((int)0x89c50201); + + /// + /// The "DataDirectory" registry value is too long in the LocalDB instance registry key. + /// + /// + /// Maps to the LOCALDB_EDETAIL_DATADIRECTORY_IS_TOO_LONG error. + /// + [SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "long", Justification = "Usage is safe.")] + public static readonly int DataDirectoryIsTooLong = unchecked((int)0x89c50202); + + /// + /// The "Parent Instance" registry value is missing in the LocalDB instance registry key. + /// + /// + /// Maps to the LOCALDB_EDETAIL_PARENT_INSTANCE_IS_MISSING error. + /// + public static readonly int ParentInstanceIsMissing = unchecked((int)0x89c50203); + + /// + /// The "Parent Instance" registry value is too long in the LocalDB instance registry key. + /// + /// + /// Maps to the LOCALDB_EDETAIL_PARENT_INSTANCE_IS_TOO_LONG error. + /// + [SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "long", Justification = "Usage is safe.")] + public static readonly int ParentInstanceIsTooLong = unchecked((int)0x89c50204); + + /// + /// Data directory for LocalDB instance is invalid. + /// + /// + /// Maps to the LOCALDB_EDETAIL_DATA_DIRECTORY_INVALID error. + /// + public static readonly int DataDirectoryInvalid = unchecked((int)0x89c50205); + + /// + /// LocalDB instance API: XEvent engine assert. + /// + /// + /// Maps to the LOCALDB_EDETAIL_XEVENT_ASSERT error. + /// + public static readonly int XEventAssert = unchecked((int)0x89c50206); + + /// + /// LocalDB instance API: XEvent error. + /// + /// + /// Maps to the LOCALDB_EDETAIL_XEVENT_ERROR error. + /// + public static readonly int XEventError = unchecked((int)0x89c50207); + + /// + /// LocalDB installation is corrupted. Reinstall the LocalDB. + /// + /// + /// Maps to the LOCALDB_EDETAIL_INSTALLATION_CORRUPTED error. + /// + public static readonly int InstallationCorrupted = unchecked((int)0x89c50208); + + /// + /// LocalDB XEvent error: cannot determine %ProgramFiles% folder location. + /// + /// + /// Maps to the LOCALDB_EDETAIL_CANNOT_GET_PROGRAM_FILES_LOCATION error. + /// + public static readonly int CannotGetProgramFilesLocation = unchecked((int)0x89c50209); + + /// + /// LocalDB XEvent error: Cannot initialize XEvent engine. + /// + /// + /// Maps to the LOCALDB_EDETAIL_XEVENT_CANNOT_INITIALIZE error. + /// + public static readonly int CannotInitializeXEvent = unchecked((int)0x89c5020a); + + /// + /// LocalDB XEvent error: Cannot find XEvents configuration file. + /// + /// + /// Maps to the LOCALDB_EDETAIL_XEVENT_CANNOT_FIND_CONF_FILE error. + /// + public static readonly int CannotFindXEventConfigFile = unchecked((int)0x89c5020b); + + /// + /// LocalDB XEvent error: Cannot configure XEvents engine with the configuration file. + /// + /// + /// Maps to the LOCALDB_EDETAIL_XEVENT_CANNOT_CONFIGURE error. + /// + public static readonly int CannotConfigureXEvent = unchecked((int)0x89c5020c); + + /// + /// LocalDB XEvent error: XEvents engine configuration file too long. + /// + /// + /// Maps to the LOCALDB_EDETAIL_XEVENT_CONF_FILE_NAME_TOO_LONG error. + /// + [SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "long", Justification = "Usage is safe.")] + public static readonly int XEventConfigFileTooLong = unchecked((int)0x89c5020d); + + /// + /// CoInitializeEx API failed. + /// + /// + /// Maps to the LOCALDB_EDETAIL_COINITIALIZEEX_FAILED error. + /// + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Co", Justification = "Is part of a function name.")] + public static readonly int CoInitializeExFailed = unchecked((int)0x89c5020e); + + /// + /// LocalDB parent instance version is invalid. + /// + /// + /// Maps to the LOCALDB_EDETAIL_PARENT_INSTANCE_VERSION_INVALID error. + /// + public static readonly int ParentInstanceVersionInvalid = unchecked((int)0x89c5020f); + + /// + /// A Windows API call returned an error. + /// + /// + /// Maps to the LOCALDB_EDETAIL_WINAPI_ERROR error. + /// + public static readonly int WindowsApiError = unchecked((int)0x89c50210); + + /// + /// Unexpected result. + /// + /// + /// Maps to the LOCALDB_EDETAIL_UNEXPECTED_RESULT error. + /// + public static readonly int UnexpectedResult = unchecked((int)0x89c50211); } diff --git a/src/SqlLocalDb/SqlLocalDbException.cs b/src/SqlLocalDb/SqlLocalDbException.cs index 7c2b764d..707925d6 100644 --- a/src/SqlLocalDb/SqlLocalDbException.cs +++ b/src/SqlLocalDb/SqlLocalDbException.cs @@ -4,151 +4,150 @@ using System.Data.Common; using System.Runtime.Serialization; -namespace MartinCostello.SqlLocalDb +namespace MartinCostello.SqlLocalDb; + +/// +/// The exception that is thrown when SQL Server LocalDB returns an error. +/// +[Serializable] +public class SqlLocalDbException : DbException { /// - /// The exception that is thrown when SQL Server LocalDB returns an error. + /// The serialization key for the property. + /// + private const string ErrorCodeKey = "SqlLocalDbException_ErrorCode"; + + /// + /// The serialization key for the property. /// - [Serializable] - public class SqlLocalDbException : DbException + private const string InstanceNameKey = "SqlLocalDbException_InstanceName"; + + /// + /// The error code associated with the exception, if any. + /// + private readonly int? _errorCode; + + /// + /// Initializes a new instance of the class. + /// + public SqlLocalDbException() + : base(SR.SqlLocalDbException_DefaultMessage) { - /// - /// The serialization key for the property. - /// - private const string ErrorCodeKey = "SqlLocalDbException_ErrorCode"; - - /// - /// The serialization key for the property. - /// - private const string InstanceNameKey = "SqlLocalDbException_InstanceName"; - - /// - /// The error code associated with the exception, if any. - /// - private readonly int? _errorCode; - - /// - /// Initializes a new instance of the class. - /// - public SqlLocalDbException() - : base(SR.SqlLocalDbException_DefaultMessage) - { - } + } - /// - /// Initializes a new instance of the class with - /// the specified error message. - /// - /// The message to display for this exception. - public SqlLocalDbException(string message) - : base(message) - { - } + /// + /// Initializes a new instance of the class with + /// the specified error message. + /// + /// The message to display for this exception. + public SqlLocalDbException(string message) + : base(message) + { + } - /// - /// Initializes a new instance of the class with - /// the specified error message and a reference to the inner exception that is - /// the cause of this exception. - /// - /// The error message string. - /// The inner exception reference. - public SqlLocalDbException(string message, Exception innerException) - : base(message, innerException) - { - } + /// + /// Initializes a new instance of the class with + /// the specified error message and a reference to the inner exception that is + /// the cause of this exception. + /// + /// The error message string. + /// The inner exception reference. + public SqlLocalDbException(string message, Exception innerException) + : base(message, innerException) + { + } - /// - /// Initializes a new instance of the class with - /// the specified error message and error code. - /// - /// The error message that explains the reason for the exception. - /// The error code for the exception. - public SqlLocalDbException(string message, int errorCode) - : base(message, errorCode) - { - } + /// + /// Initializes a new instance of the class with + /// the specified error message and error code. + /// + /// The error message that explains the reason for the exception. + /// The error code for the exception. + public SqlLocalDbException(string message, int errorCode) + : base(message, errorCode) + { + } - /// - /// Initializes a new instance of the class with - /// the specified error message and error code. - /// - /// The error message that explains the reason for the exception. - /// The error code for the exception. - /// The name of the LocalDB instance that caused the exception, if any. - public SqlLocalDbException(string message, int errorCode, string? instanceName) - : base(message, errorCode) - { - InstanceName = instanceName; - } + /// + /// Initializes a new instance of the class with + /// the specified error message and error code. + /// + /// The error message that explains the reason for the exception. + /// The error code for the exception. + /// The name of the LocalDB instance that caused the exception, if any. + public SqlLocalDbException(string message, int errorCode, string? instanceName) + : base(message, errorCode) + { + InstanceName = instanceName; + } - /// - /// Initializes a new instance of the class with - /// the specified error message and error code. - /// - /// The error message that explains the reason for the exception. - /// The error code for the exception. - /// The name of the LocalDB instance that caused the exception, if any. - /// The inner exception reference. - public SqlLocalDbException(string message, int errorCode, string? instanceName, Exception innerException) - : base(message, innerException) - { - // Set local value as no way to pass both errorCode and innerException to base class - _errorCode = errorCode; - InstanceName = instanceName; - } + /// + /// Initializes a new instance of the class with + /// the specified error message and error code. + /// + /// The error message that explains the reason for the exception. + /// The error code for the exception. + /// The name of the LocalDB instance that caused the exception, if any. + /// The inner exception reference. + public SqlLocalDbException(string message, int errorCode, string? instanceName, Exception innerException) + : base(message, innerException) + { + // Set local value as no way to pass both errorCode and innerException to base class + _errorCode = errorCode; + InstanceName = instanceName; + } - /// - /// Initializes a new instance of the class with - /// the specified serialization information and context. - /// - /// - /// The that holds - /// the serialized object data about the exception being thrown. - /// - /// - /// The that contains - /// contextual information about the source or destination. - /// - /// - /// is . - /// - protected SqlLocalDbException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - _errorCode = (int?)info.GetValue(ErrorCodeKey, typeof(int?)); - InstanceName = info.GetString(InstanceNameKey); - } + /// + /// Initializes a new instance of the class with + /// the specified serialization information and context. + /// + /// + /// The that holds + /// the serialized object data about the exception being thrown. + /// + /// + /// The that contains + /// contextual information about the source or destination. + /// + /// + /// is . + /// + protected SqlLocalDbException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + _errorCode = (int?)info.GetValue(ErrorCodeKey, typeof(int?)); + InstanceName = info.GetString(InstanceNameKey); + } - /// - /// Gets the HRESULT of the error. - /// - public override int ErrorCode => _errorCode ?? base.ErrorCode; - - /// - /// Gets or sets the name of the SQL Server LocalDB - /// instance that caused the exception, if any. - /// - public string? InstanceName { get; protected set; } - - /// - /// Sets the with information about the exception. - /// - /// The that holds the serialized object data about the exception being thrown. - /// The that contains contextual information about the source or destination. - /// - /// The parameter is . - /// - public override void GetObjectData(SerializationInfo info, StreamingContext context) - { - if (info == null) - { - throw new ArgumentNullException(nameof(info)); - } + /// + /// Gets the HRESULT of the error. + /// + public override int ErrorCode => _errorCode ?? base.ErrorCode; - base.GetObjectData(info, context); + /// + /// Gets or sets the name of the SQL Server LocalDB + /// instance that caused the exception, if any. + /// + public string? InstanceName { get; protected set; } - info.AddValue(ErrorCodeKey, _errorCode); - info.AddValue(InstanceNameKey, InstanceName); + /// + /// Sets the with information about the exception. + /// + /// The that holds the serialized object data about the exception being thrown. + /// The that contains contextual information about the source or destination. + /// + /// The parameter is . + /// + public override void GetObjectData(SerializationInfo info, StreamingContext context) + { + if (info == null) + { + throw new ArgumentNullException(nameof(info)); } + + base.GetObjectData(info, context); + + info.AddValue(ErrorCodeKey, _errorCode); + info.AddValue(InstanceNameKey, InstanceName); } } diff --git a/src/SqlLocalDb/SqlLocalDbInstanceInfo.cs b/src/SqlLocalDb/SqlLocalDbInstanceInfo.cs index af79fcdb..f87a7163 100644 --- a/src/SqlLocalDb/SqlLocalDbInstanceInfo.cs +++ b/src/SqlLocalDb/SqlLocalDbInstanceInfo.cs @@ -3,93 +3,92 @@ using System.Diagnostics; -namespace MartinCostello.SqlLocalDb +namespace MartinCostello.SqlLocalDb; + +/// +/// A class representing information about an instance of SQL LocalDB. This class cannot be inherited. +/// +[DebuggerDisplay("{Name}")] +internal sealed class SqlLocalDbInstanceInfo : ISqlLocalDbInstanceInfo, ISqlLocalDbApiAdapter { + //// Internally created type used to provide "pit-of-success" semantics on + //// instances of ISqlLocalDbInstanceInfo so that the state can be updated + //// during mutations of the API without returning marshalled types directly. + /// - /// A class representing information about an instance of SQL LocalDB. This class cannot be inherited. + /// Initializes a new instance of the class. /// - [DebuggerDisplay("{Name}")] - internal sealed class SqlLocalDbInstanceInfo : ISqlLocalDbInstanceInfo, ISqlLocalDbApiAdapter + /// The associated with the instance. + internal SqlLocalDbInstanceInfo(ISqlLocalDbApi api) { - //// Internally created type used to provide "pit-of-success" semantics on - //// instances of ISqlLocalDbInstanceInfo so that the state can be updated - //// during mutations of the API without returning marshalled types directly. - - /// - /// Initializes a new instance of the class. - /// - /// The associated with the instance. - internal SqlLocalDbInstanceInfo(ISqlLocalDbApi api) - { - Api = api; - } + Api = api; + } - /// - public bool ConfigurationCorrupt { get; internal set; } + /// + public bool ConfigurationCorrupt { get; internal set; } - /// - public bool Exists { get; internal set; } + /// + public bool Exists { get; internal set; } - /// - public bool IsAutomatic { get; internal set; } + /// + public bool IsAutomatic { get; internal set; } - /// - public bool IsRunning { get; internal set; } + /// + public bool IsRunning { get; internal set; } - /// - public bool IsShared { get; internal set; } + /// + public bool IsShared { get; internal set; } - /// - public DateTime LastStartTimeUtc { get; internal set; } + /// + public DateTime LastStartTimeUtc { get; internal set; } - /// - public Version LocalDbVersion { get; internal set; } = new Version(); + /// + public Version LocalDbVersion { get; internal set; } = new Version(); - /// - public string Name { get; internal set; } = string.Empty; + /// + public string Name { get; internal set; } = string.Empty; - /// - public string NamedPipe { get; internal set; } = string.Empty; + /// + public string NamedPipe { get; internal set; } = string.Empty; - /// - public string OwnerSid { get; internal set; } = string.Empty; + /// + public string OwnerSid { get; internal set; } = string.Empty; - /// - public string SharedName { get; internal set; } = string.Empty; + /// + public string SharedName { get; internal set; } = string.Empty; - /// - ISqlLocalDbApi ISqlLocalDbApiAdapter.LocalDb => Api; + /// + ISqlLocalDbApi ISqlLocalDbApiAdapter.LocalDb => Api; - /// - /// Gets the associated with this instance. - /// - private ISqlLocalDbApi Api { get; } + /// + /// Gets the associated with this instance. + /// + private ISqlLocalDbApi Api { get; } - /// - public override string ToString() => Name; + /// + public override string ToString() => Name; - /// - /// Updates the state of the instance from the specified value. - /// - /// The other value to use to update the instance's state. - internal void Update(ISqlLocalDbInstanceInfo other) + /// + /// Updates the state of the instance from the specified value. + /// + /// The other value to use to update the instance's state. + internal void Update(ISqlLocalDbInstanceInfo other) + { + if (other == null || ReferenceEquals(other, this)) { - if (other == null || ReferenceEquals(other, this)) - { - return; - } - - ConfigurationCorrupt = other.ConfigurationCorrupt; - Exists = other.Exists; - IsAutomatic = other.IsAutomatic; - IsRunning = other.IsRunning; - IsShared = other.IsShared; - LastStartTimeUtc = other.LastStartTimeUtc; - LocalDbVersion = other.LocalDbVersion; - Name = other.Name; - NamedPipe = other.NamedPipe; - OwnerSid = other.OwnerSid; - SharedName = other.SharedName; + return; } + + ConfigurationCorrupt = other.ConfigurationCorrupt; + Exists = other.Exists; + IsAutomatic = other.IsAutomatic; + IsRunning = other.IsRunning; + IsShared = other.IsShared; + LastStartTimeUtc = other.LastStartTimeUtc; + LocalDbVersion = other.LocalDbVersion; + Name = other.Name; + NamedPipe = other.NamedPipe; + OwnerSid = other.OwnerSid; + SharedName = other.SharedName; } } diff --git a/src/SqlLocalDb/SqlLocalDbInstanceManager.cs b/src/SqlLocalDb/SqlLocalDbInstanceManager.cs index 3292b7b9..3592cb55 100644 --- a/src/SqlLocalDb/SqlLocalDbInstanceManager.cs +++ b/src/SqlLocalDb/SqlLocalDbInstanceManager.cs @@ -3,165 +3,164 @@ using System.Diagnostics; -namespace MartinCostello.SqlLocalDb +namespace MartinCostello.SqlLocalDb; + +/// +/// A class that can be used to manage instances of SQL LocalDB. This class cannot be inherited. +/// +[DebuggerDisplay("{Name}")] +public sealed class SqlLocalDbInstanceManager : ISqlLocalDbInstanceManager, ISqlLocalDbApiAdapter { /// - /// A class that can be used to manage instances of SQL LocalDB. This class cannot be inherited. + /// Initializes a new instance of the class. /// - [DebuggerDisplay("{Name}")] - public sealed class SqlLocalDbInstanceManager : ISqlLocalDbInstanceManager, ISqlLocalDbApiAdapter + /// The SQL Server LocalDB instance to manage. + /// The instance to use. + /// + /// or is . + /// + public SqlLocalDbInstanceManager(ISqlLocalDbInstanceInfo instance, ISqlLocalDbApi api) { - /// - /// Initializes a new instance of the class. - /// - /// The SQL Server LocalDB instance to manage. - /// The instance to use. - /// - /// or is . - /// - public SqlLocalDbInstanceManager(ISqlLocalDbInstanceInfo instance, ISqlLocalDbApi api) - { - Instance = instance ?? throw new ArgumentNullException(nameof(instance)); - Api = api ?? throw new ArgumentNullException(nameof(api)); - } + Instance = instance ?? throw new ArgumentNullException(nameof(instance)); + Api = api ?? throw new ArgumentNullException(nameof(api)); + } - /// - public string Name => Instance.Name; + /// + public string Name => Instance.Name; - /// - public string NamedPipe => Instance.NamedPipe; + /// + public string NamedPipe => Instance.NamedPipe; - /// - ISqlLocalDbApi ISqlLocalDbApiAdapter.LocalDb => Api; + /// + ISqlLocalDbApi ISqlLocalDbApiAdapter.LocalDb => Api; - /// - /// Gets the to use. - /// - private ISqlLocalDbApi Api { get; } + /// + /// Gets the to use. + /// + private ISqlLocalDbApi Api { get; } - /// - /// Gets the in use. - /// - private ISqlLocalDbInstanceInfo Instance { get; } + /// + /// Gets the in use. + /// + private ISqlLocalDbInstanceInfo Instance { get; } - /// - /// Gets the current state of the instance. - /// - /// - /// An representing the current state of the instance being managed. - /// - public ISqlLocalDbInstanceInfo GetInstanceInfo() => Api.GetInstanceInfo(Name); + /// + /// Gets the current state of the instance. + /// + /// + /// An representing the current state of the instance being managed. + /// + public ISqlLocalDbInstanceInfo GetInstanceInfo() => Api.GetInstanceInfo(Name); - /// - /// Shares the LocalDB instance using the specified name. - /// - /// The name to use to share the instance. - /// - /// is . - /// - /// - /// The LocalDB instance could not be shared. - /// - public void Share(string sharedName) + /// + /// Shares the LocalDB instance using the specified name. + /// + /// The name to use to share the instance. + /// + /// is . + /// + /// + /// The LocalDB instance could not be shared. + /// + public void Share(string sharedName) + { + if (sharedName == null) { - if (sharedName == null) - { - throw new ArgumentNullException(nameof(sharedName)); - } + throw new ArgumentNullException(nameof(sharedName)); + } - try - { - Api.ShareInstance(Name, sharedName); - UpdateState(); - } - catch (SqlLocalDbException ex) - { - throw new SqlLocalDbException( - SRHelper.Format(SR.SqlLocalDbInstanceManager_ShareFailedFormat, Name), - ex.ErrorCode, - ex.InstanceName, - ex); - } + try + { + Api.ShareInstance(Name, sharedName); + UpdateState(); } + catch (SqlLocalDbException ex) + { + throw new SqlLocalDbException( + SRHelper.Format(SR.SqlLocalDbInstanceManager_ShareFailedFormat, Name), + ex.ErrorCode, + ex.InstanceName, + ex); + } + } - /// - /// Starts the SQL Server LocalDB instance. - /// - /// - /// The LocalDB instance could not be started. - /// - public void Start() + /// + /// Starts the SQL Server LocalDB instance. + /// + /// + /// The LocalDB instance could not be started. + /// + public void Start() + { + try + { + Api.StartInstance(Name); + UpdateState(); + } + catch (SqlLocalDbException ex) { - try - { - Api.StartInstance(Name); - UpdateState(); - } - catch (SqlLocalDbException ex) - { - throw new SqlLocalDbException( - SRHelper.Format(SR.SqlLocalDbInstanceManager_StartFailedFormat, Name), - ex.ErrorCode, - ex.InstanceName, - ex); - } + throw new SqlLocalDbException( + SRHelper.Format(SR.SqlLocalDbInstanceManager_StartFailedFormat, Name), + ex.ErrorCode, + ex.InstanceName, + ex); } + } - /// - /// Stops the SQL Server LocalDB instance. - /// - /// - /// The LocalDB instance could not be stopped. - /// - public void Stop() + /// + /// Stops the SQL Server LocalDB instance. + /// + /// + /// The LocalDB instance could not be stopped. + /// + public void Stop() + { + try { - try - { - Api.StopInstance(Name, null); - UpdateState(); - } - catch (SqlLocalDbException ex) - { - throw new SqlLocalDbException( - SRHelper.Format(SR.SqlLocalDbInstanceManager_StopFailedFormat, Name), - ex.ErrorCode, - ex.InstanceName, - ex); - } + Api.StopInstance(Name, null); + UpdateState(); } + catch (SqlLocalDbException ex) + { + throw new SqlLocalDbException( + SRHelper.Format(SR.SqlLocalDbInstanceManager_StopFailedFormat, Name), + ex.ErrorCode, + ex.InstanceName, + ex); + } + } - /// - /// Stops sharing the LocalDB instance. - /// - /// - /// The LocalDB instance could not be unshared. - /// - public void Unshare() + /// + /// Stops sharing the LocalDB instance. + /// + /// + /// The LocalDB instance could not be unshared. + /// + public void Unshare() + { + try + { + Api.UnshareInstance(Name); + UpdateState(); + } + catch (SqlLocalDbException ex) { - try - { - Api.UnshareInstance(Name); - UpdateState(); - } - catch (SqlLocalDbException ex) - { - throw new SqlLocalDbException( - SRHelper.Format(SR.SqlLocalDbInstanceManager_UnshareFailedFormat, Name), - ex.ErrorCode, - ex.InstanceName, - ex); - } + throw new SqlLocalDbException( + SRHelper.Format(SR.SqlLocalDbInstanceManager_UnshareFailedFormat, Name), + ex.ErrorCode, + ex.InstanceName, + ex); } + } - /// - /// Updates the state of , if possible. - /// - private void UpdateState() + /// + /// Updates the state of , if possible. + /// + private void UpdateState() + { + if (Instance is SqlLocalDbInstanceInfo info) { - if (Instance is SqlLocalDbInstanceInfo info) - { - info.Update(Api.GetInstanceInfo(info.Name)); - } + info.Update(Api.GetInstanceInfo(info.Name)); } } } diff --git a/src/SqlLocalDb/SqlLocalDbOptions.cs b/src/SqlLocalDb/SqlLocalDbOptions.cs index bbe8c13b..da39357f 100644 --- a/src/SqlLocalDb/SqlLocalDbOptions.cs +++ b/src/SqlLocalDb/SqlLocalDbOptions.cs @@ -1,79 +1,78 @@ // Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -namespace MartinCostello.SqlLocalDb +namespace MartinCostello.SqlLocalDb; + +/// +/// A class representing options for using the SQL LocalDB API. +/// +public class SqlLocalDbOptions { /// - /// A class representing options for using the SQL LocalDB API. + /// Initializes a new instance of the class. /// - public class SqlLocalDbOptions + public SqlLocalDbOptions() { - /// - /// Initializes a new instance of the class. - /// - public SqlLocalDbOptions() - { - } + } - /// - /// Gets or sets a value indicating whether to automatically delete the - /// files associated with SQL LocalDB instances when they are deleted. - /// - /// - /// The default value is . - /// - public bool AutomaticallyDeleteInstanceFiles { get; set; } + /// + /// Gets or sets a value indicating whether to automatically delete the + /// files associated with SQL LocalDB instances when they are deleted. + /// + /// + /// The default value is . + /// + public bool AutomaticallyDeleteInstanceFiles { get; set; } - /// - /// Gets or sets the override language to use to format error messages. - /// - public CultureInfo? Language { get; set; } + /// + /// Gets or sets the override language to use to format error messages. + /// + public CultureInfo? Language { get; set; } - /// - /// Gets or sets the override version string of the native SQL LocalDB API to load, if any. - /// - public string NativeApiOverrideVersion { get; set; } = string.Empty; + /// + /// Gets or sets the override version string of the native SQL LocalDB API to load, if any. + /// + public string NativeApiOverrideVersion { get; set; } = string.Empty; - /// - /// Gets or sets the options to use when stopping instances of SQL LocalDB. - /// - /// - /// The default value is . - /// - public StopInstanceOptions StopOptions { get; set; } = StopInstanceOptions.None; + /// + /// Gets or sets the options to use when stopping instances of SQL LocalDB. + /// + /// + /// The default value is . + /// + public StopInstanceOptions StopOptions { get; set; } = StopInstanceOptions.None; - /// - /// Gets or sets the default timeout to use when stopping instances of SQL LocalDB. - /// - /// - /// The default value is 1 minute. - /// - public TimeSpan StopTimeout { get; set; } = TimeSpan.FromMinutes(1); + /// + /// Gets or sets the default timeout to use when stopping instances of SQL LocalDB. + /// + /// + /// The default value is 1 minute. + /// + public TimeSpan StopTimeout { get; set; } = TimeSpan.FromMinutes(1); - /// - /// Gets the locale ID (LCID) to use for formatting error messages. - /// - internal int LanguageId + /// + /// Gets the locale ID (LCID) to use for formatting error messages. + /// + internal int LanguageId + { + get { - get - { - CultureInfo? culture = Language; - - if (culture == null) - { - // Zero is used by SQL LocalDB to mean to defer to the OS configuration - return 0; - } + CultureInfo? culture = Language; - // N.B. No checks as to the support of the configured culture's LCID for use - // by SQL LocalDB are made here, it is left to the user to ensure that the - // culture code they configure is supported. From experimentation, SQL LocalDB - // supports the "main" language/region for cultures and not the neutral culture. - // For example: - // Supported: de-DE, en-US, es-ES, fr-FR; - // Not supported: de, en, en-GB, es, es-MX, fr, fr-CA. - return culture.LCID; + if (culture == null) + { + // Zero is used by SQL LocalDB to mean to defer to the OS configuration + return 0; } + + // N.B. No checks as to the support of the configured culture's LCID for use + // by SQL LocalDB are made here, it is left to the user to ensure that the + // culture code they configure is supported. From experimentation, SQL LocalDB + // supports the "main" language/region for cultures and not the neutral culture. + // For example: + // Supported: de-DE, en-US, es-ES, fr-FR; + // Not supported: de, en, en-GB, es, es-MX, fr, fr-CA. + return culture.LCID; } } } diff --git a/src/SqlLocalDb/SqlLocalDbServiceCollectionExtensions.cs b/src/SqlLocalDb/SqlLocalDbServiceCollectionExtensions.cs index 9c7dde28..f76bf680 100644 --- a/src/SqlLocalDb/SqlLocalDbServiceCollectionExtensions.cs +++ b/src/SqlLocalDb/SqlLocalDbServiceCollectionExtensions.cs @@ -6,122 +6,121 @@ using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Logging; -namespace Microsoft.Extensions.DependencyInjection +namespace Microsoft.Extensions.DependencyInjection; + +/// +/// A class containing extension methods for the interface. This class cannot be inherited. +/// +[EditorBrowsable(EditorBrowsableState.Never)] +public static class SqlLocalDbServiceCollectionExtensions { /// - /// A class containing extension methods for the interface. This class cannot be inherited. + /// Adds SQL Server LocalDB services. + /// + /// The to add services to. + /// + /// The passed as the value of . + /// + /// + /// is . + /// + public static IServiceCollection AddSqlLocalDB(this IServiceCollection services) + => services.AddSqlLocalDB((_) => { }); + + /// + /// Adds SQL Server LocalDB services. /// - [EditorBrowsable(EditorBrowsableState.Never)] - public static class SqlLocalDbServiceCollectionExtensions + /// The to add services to. + /// A delegate to a method to use to configure the SQL Server LocalDB options. + /// + /// The passed as the value of . + /// + /// + /// or is . + /// + public static IServiceCollection AddSqlLocalDB(this IServiceCollection services, Action configure) { - /// - /// Adds SQL Server LocalDB services. - /// - /// The to add services to. - /// - /// The passed as the value of . - /// - /// - /// is . - /// - public static IServiceCollection AddSqlLocalDB(this IServiceCollection services) - => services.AddSqlLocalDB((_) => { }); - - /// - /// Adds SQL Server LocalDB services. - /// - /// The to add services to. - /// A delegate to a method to use to configure the SQL Server LocalDB options. - /// - /// The passed as the value of . - /// - /// - /// or is . - /// - public static IServiceCollection AddSqlLocalDB(this IServiceCollection services, Action configure) + if (services == null) { - if (services == null) - { - throw new ArgumentNullException(nameof(services)); - } + throw new ArgumentNullException(nameof(services)); + } + + if (configure == null) + { + throw new ArgumentNullException(nameof(configure)); + } - if (configure == null) + return services.AddSqlLocalDB( + (_) => { - throw new ArgumentNullException(nameof(configure)); - } + var options = new SqlLocalDbOptions(); - return services.AddSqlLocalDB( - (_) => - { - var options = new SqlLocalDbOptions(); + configure(options); - configure(options); + return options; + }); + } - return options; - }); + /// + /// Adds SQL Server LocalDB services. + /// + /// The to add services to. + /// A delegate to a method to use to configure the SQL Server LocalDB options. + /// + /// The passed as the value of . + /// + /// + /// or is . + /// + public static IServiceCollection AddSqlLocalDB(this IServiceCollection services, Func configure) + { + if (services == null) + { + throw new ArgumentNullException(nameof(services)); } - /// - /// Adds SQL Server LocalDB services. - /// - /// The to add services to. - /// A delegate to a method to use to configure the SQL Server LocalDB options. - /// - /// The passed as the value of . - /// - /// - /// or is . - /// - public static IServiceCollection AddSqlLocalDB(this IServiceCollection services, Func configure) + if (configure == null) { - if (services == null) - { - throw new ArgumentNullException(nameof(services)); - } + throw new ArgumentNullException(nameof(configure)); + } - if (configure == null) - { - throw new ArgumentNullException(nameof(configure)); - } + services.TryAddSingleton(configure); - services.TryAddSingleton(configure); + services.TryAddSingleton( + (p) => + { + var options = p.GetRequiredService(); + var loggerFactory = p.GetRequiredService(); - services.TryAddSingleton( - (p) => - { - var options = p.GetRequiredService(); - var loggerFactory = p.GetRequiredService(); + return new SqlLocalDbApi(options, loggerFactory); + }); - return new SqlLocalDbApi(options, loggerFactory); - }); + return services; + } - return services; + /// + /// Adds SQL Server LocalDB services. + /// + /// The to add services to. + /// The SQL Server LocalDB options to use. + /// + /// The passed as the value of . + /// + /// + /// or is . + /// + public static IServiceCollection AddSqlLocalDB(this IServiceCollection services, SqlLocalDbOptions options) + { + if (services == null) + { + throw new ArgumentNullException(nameof(services)); } - /// - /// Adds SQL Server LocalDB services. - /// - /// The to add services to. - /// The SQL Server LocalDB options to use. - /// - /// The passed as the value of . - /// - /// - /// or is . - /// - public static IServiceCollection AddSqlLocalDB(this IServiceCollection services, SqlLocalDbOptions options) + if (options == null) { - if (services == null) - { - throw new ArgumentNullException(nameof(services)); - } - - if (options == null) - { - throw new ArgumentNullException(nameof(options)); - } - - return services.AddSqlLocalDB((_) => options); + throw new ArgumentNullException(nameof(options)); } + + return services.AddSqlLocalDB((_) => options); } } diff --git a/src/SqlLocalDb/SqlLocalDbVersionInfo.cs b/src/SqlLocalDb/SqlLocalDbVersionInfo.cs index e39888cb..c14ca432 100644 --- a/src/SqlLocalDb/SqlLocalDbVersionInfo.cs +++ b/src/SqlLocalDb/SqlLocalDbVersionInfo.cs @@ -3,47 +3,46 @@ using System.Diagnostics; -namespace MartinCostello.SqlLocalDb +namespace MartinCostello.SqlLocalDb; + +/// +/// A class representing information about a version of SQL Server LocalDB. This class cannot be inherited. +/// +[DebuggerDisplay("{Name}")] +internal sealed class SqlLocalDbVersionInfo : ISqlLocalDbVersionInfo { /// - /// A class representing information about a version of SQL Server LocalDB. This class cannot be inherited. + /// Initializes a new instance of the class. /// - [DebuggerDisplay("{Name}")] - internal sealed class SqlLocalDbVersionInfo : ISqlLocalDbVersionInfo + internal SqlLocalDbVersionInfo() { - /// - /// Initializes a new instance of the class. - /// - internal SqlLocalDbVersionInfo() - { - } + } - /// - public bool Exists { get; internal set; } + /// + public bool Exists { get; internal set; } - /// - public string Name { get; internal set; } = string.Empty; + /// + public string Name { get; internal set; } = string.Empty; - /// - public Version Version { get; internal set; } = new Version(); + /// + public Version Version { get; internal set; } = new Version(); - /// - public override string ToString() => Name; + /// + public override string ToString() => Name; - /// - /// Updates the state of the instance from the specified value. - /// - /// The other value to use to update the instance's state. - internal void Update(ISqlLocalDbVersionInfo other) + /// + /// Updates the state of the instance from the specified value. + /// + /// The other value to use to update the instance's state. + internal void Update(ISqlLocalDbVersionInfo other) + { + if (other == null || ReferenceEquals(other, this)) { - if (other == null || ReferenceEquals(other, this)) - { - return; - } - - Exists = other.Exists; - Name = other.Name; - Version = other.Version; + return; } + + Exists = other.Exists; + Name = other.Name; + Version = other.Version; } } diff --git a/src/SqlLocalDb/StopInstanceOptions.cs b/src/SqlLocalDb/StopInstanceOptions.cs index 4c5539f6..e68a0ecc 100644 --- a/src/SqlLocalDb/StopInstanceOptions.cs +++ b/src/SqlLocalDb/StopInstanceOptions.cs @@ -1,27 +1,26 @@ // Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -namespace MartinCostello.SqlLocalDb +namespace MartinCostello.SqlLocalDb; + +/// +/// An enumeration of options to control the behavior when stopping a SQL LocalDB instance. +/// +[Flags] +public enum StopInstanceOptions { /// - /// An enumeration of options to control the behavior when stopping a SQL LocalDB instance. + /// Shut down using the SHUTDOWN Transact-SQL command. /// - [Flags] - public enum StopInstanceOptions - { - /// - /// Shut down using the SHUTDOWN Transact-SQL command. - /// - None = 0, + None = 0, - /// - /// Shut down immediately using the kill process operating system command. - /// - KillProcess = 1, + /// + /// Shut down immediately using the kill process operating system command. + /// + KillProcess = 1, - /// - /// Shut down using the WITH NOWAIT option Transact-SQL command. - /// - NoWait = 2, - } + /// + /// Shut down using the WITH NOWAIT option Transact-SQL command. + /// + NoWait = 2, } diff --git a/src/SqlLocalDb/TemporarySqlLocalDbInstance.cs b/src/SqlLocalDb/TemporarySqlLocalDbInstance.cs index 88a1000f..e4295ebc 100644 --- a/src/SqlLocalDb/TemporarySqlLocalDbInstance.cs +++ b/src/SqlLocalDb/TemporarySqlLocalDbInstance.cs @@ -3,225 +3,224 @@ using Microsoft.Extensions.Logging; -namespace MartinCostello.SqlLocalDb +namespace MartinCostello.SqlLocalDb; + +/// +/// A class representing a temporary SQL LocalDB instance. This class cannot be inherited. +/// +/// +/// The temporary SQL LocalDB instances that are created by instances of this class are automatically +/// started when they are instantiated, and are then subsequently deleted when they are disposed of. +/// +public sealed class TemporarySqlLocalDbInstance : IDisposable, ISqlLocalDbApiAdapter { /// - /// A class representing a temporary SQL LocalDB instance. This class cannot be inherited. + /// The lazily initialized name of the temporary SQL LocalDB instance. This field is read-only. /// - /// - /// The temporary SQL LocalDB instances that are created by instances of this class are automatically - /// started when they are instantiated, and are then subsequently deleted when they are disposed of. - /// - public sealed class TemporarySqlLocalDbInstance : IDisposable, ISqlLocalDbApiAdapter + private readonly Lazy _instanceName; + + /// + /// Whether the instance has been disposed. + /// + private bool _disposed; + + /// + /// The to use, if any. + /// + private ILogger? _logger; + + /// + /// Initializes a new instance of the class. + /// + /// The to use to create the temporary instance. + /// Whether to delete the file(s) associated with the SQL LocalDB instance when deleted. + /// + /// is . + /// + internal TemporarySqlLocalDbInstance(ISqlLocalDbApi api, bool deleteFiles) { - /// - /// The lazily initialized name of the temporary SQL LocalDB instance. This field is read-only. - /// - private readonly Lazy _instanceName; - - /// - /// Whether the instance has been disposed. - /// - private bool _disposed; - - /// - /// The to use, if any. - /// - private ILogger? _logger; - - /// - /// Initializes a new instance of the class. - /// - /// The to use to create the temporary instance. - /// Whether to delete the file(s) associated with the SQL LocalDB instance when deleted. - /// - /// is . - /// - internal TemporarySqlLocalDbInstance(ISqlLocalDbApi api, bool deleteFiles) - { - Api = api ?? throw new ArgumentNullException(nameof(api)); - DeleteFiles = deleteFiles; - _instanceName = new Lazy(EnsureInitialized); - } + Api = api ?? throw new ArgumentNullException(nameof(api)); + DeleteFiles = deleteFiles; + _instanceName = new Lazy(EnsureInitialized); + } - /// - /// Finalizes an instance of the class. - /// - ~TemporarySqlLocalDbInstance() - { - DisposeInternal(); - } + /// + /// Finalizes an instance of the class. + /// + ~TemporarySqlLocalDbInstance() + { + DisposeInternal(); + } - /// - /// Gets the connection string for the temporary SQL LocalDB instance. - /// - /// - /// Thrown if the instance has been disposed of. - /// - public string ConnectionString => GetInstanceInfo().GetConnectionString(); - - /// - /// Gets the name of the temporary SQL LocalDB instance. - /// - /// - /// Thrown if the instance has been disposed of. - /// - public string Name + /// + /// Gets the connection string for the temporary SQL LocalDB instance. + /// + /// + /// Thrown if the instance has been disposed of. + /// + public string ConnectionString => GetInstanceInfo().GetConnectionString(); + + /// + /// Gets the name of the temporary SQL LocalDB instance. + /// + /// + /// Thrown if the instance has been disposed of. + /// + public string Name + { + get { - get - { - EnsureNotDisposed(); - return _instanceName.Value; - } + EnsureNotDisposed(); + return _instanceName.Value; } + } - /// - ISqlLocalDbApi ISqlLocalDbApiAdapter.LocalDb => Api; + /// + ISqlLocalDbApi ISqlLocalDbApiAdapter.LocalDb => Api; - /// - /// Gets the to use. - /// - private ISqlLocalDbApi Api { get; } + /// + /// Gets the to use. + /// + private ISqlLocalDbApi Api { get; } - /// - /// Gets a value indicating whether to delete the instance file(s) when the instance is disposed of. - /// - private bool DeleteFiles { get; } + /// + /// Gets a value indicating whether to delete the instance file(s) when the instance is disposed of. + /// + private bool DeleteFiles { get; } - /// - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// - public void Dispose() - { - DisposeInternal(); - GC.SuppressFinalize(this); - } + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + public void Dispose() + { + DisposeInternal(); + GC.SuppressFinalize(this); + } + + /// + /// Gets the temporary SQL LocalDB instance. + /// + /// + /// An representing the temporary SQL LocalDB instance. + /// + /// + /// Thrown if the instance has been disposed of. + /// + public ISqlLocalDbInstanceInfo GetInstanceInfo() => Api.GetInstanceInfo(Name); - /// - /// Gets the temporary SQL LocalDB instance. - /// - /// - /// An representing the temporary SQL LocalDB instance. - /// - /// - /// Thrown if the instance has been disposed of. - /// - public ISqlLocalDbInstanceInfo GetInstanceInfo() => Api.GetInstanceInfo(Name); - - /// - /// Returns an that can be used to manage the instance. - /// - /// - /// An that can be used to manage the temporary SQL LocalDB instance. - /// - /// - /// Thrown if the instance has been disposed of. - /// - public ISqlLocalDbInstanceManager Manage() => GetInstanceInfo().Manage(); - - /// - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// - private void DisposeInternal() + /// + /// Returns an that can be used to manage the instance. + /// + /// + /// An that can be used to manage the temporary SQL LocalDB instance. + /// + /// + /// Thrown if the instance has been disposed of. + /// + public ISqlLocalDbInstanceManager Manage() => GetInstanceInfo().Manage(); + + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + private void DisposeInternal() + { + if (!_disposed) { - if (!_disposed) + if (_instanceName != null && _instanceName.IsValueCreated) { - if (_instanceName != null && _instanceName.IsValueCreated) - { - string instanceName = _instanceName.Value; + string instanceName = _instanceName.Value; - try - { - Api.StopInstance(instanceName, timeout: null); - } - catch (SqlLocalDbException ex) + try + { + Api.StopInstance(instanceName, timeout: null); + } + catch (SqlLocalDbException ex) + { + // Ignore the exception if we could not stop the instance + // because it does not exist, otherwise log the error. + if (ex.ErrorCode != SqlLocalDbErrors.UnknownInstance) { - // Ignore the exception if we could not stop the instance - // because it does not exist, otherwise log the error. - if (ex.ErrorCode != SqlLocalDbErrors.UnknownInstance) - { - _logger?.StoppingTemporaryInstanceFailed(instanceName, ex.ErrorCode); - } + _logger?.StoppingTemporaryInstanceFailed(instanceName, ex.ErrorCode); } + } - try - { - DeleteInstance(instanceName); - } - catch (SqlLocalDbException ex) + try + { + DeleteInstance(instanceName); + } + catch (SqlLocalDbException ex) + { + // Ignore the exception if we could not delete the instance because it was still in use + if (ex.ErrorCode != SqlLocalDbErrors.InstanceBusy) { - // Ignore the exception if we could not delete the instance because it was still in use - if (ex.ErrorCode != SqlLocalDbErrors.InstanceBusy) - { - _logger?.DeletingInstanceFailed(instanceName, ex.ErrorCode); - } + _logger?.DeletingInstanceFailed(instanceName, ex.ErrorCode); } } - - _disposed = true; } + + _disposed = true; } + } - /// - /// Ensures that the instance has been initialized. - /// - /// - /// The name of the SQL LocalDB instance that was created. - /// - private string EnsureInitialized() - { - ILoggerFactory? loggerFactory = null; + /// + /// Ensures that the instance has been initialized. + /// + /// + /// The name of the SQL LocalDB instance that was created. + /// + private string EnsureInitialized() + { + ILoggerFactory? loggerFactory = null; - if (Api is SqlLocalDbApi localDB) - { - loggerFactory = localDB.LoggerFactory; - } + if (Api is SqlLocalDbApi localDB) + { + loggerFactory = localDB.LoggerFactory; + } - _logger = loggerFactory?.CreateLogger(); + _logger = loggerFactory?.CreateLogger(); - string instanceName = Guid.NewGuid().ToString(); - Api.CreateInstance(instanceName, Api.LatestVersion); + string instanceName = Guid.NewGuid().ToString(); + Api.CreateInstance(instanceName, Api.LatestVersion); - try - { - Api.StartInstance(instanceName); - return instanceName; - } - catch (Exception) - { - DeleteInstance(instanceName); - throw; - } + try + { + Api.StartInstance(instanceName); + return instanceName; + } + catch (Exception) + { + DeleteInstance(instanceName); + throw; } + } - /// - /// Ensures that the instance has not been disposed of. - /// - /// - /// The instance has been disposed. - /// - private void EnsureNotDisposed() + /// + /// Ensures that the instance has not been disposed of. + /// + /// + /// The instance has been disposed. + /// + private void EnsureNotDisposed() + { + if (_disposed) { - if (_disposed) - { - throw new ObjectDisposedException(GetType().FullName); - } + throw new ObjectDisposedException(GetType().FullName); } + } - /// - /// Deletes the specified SQL LocalDB instance. - /// - /// The SQL LocalDB instance to delete. - private void DeleteInstance(string instanceName) + /// + /// Deletes the specified SQL LocalDB instance. + /// + /// The SQL LocalDB instance to delete. + private void DeleteInstance(string instanceName) + { + if (Api is SqlLocalDbApi localDB) { - if (Api is SqlLocalDbApi localDB) - { - localDB.DeleteInstanceInternal(instanceName, throwIfNotFound: false, deleteFiles: DeleteFiles); - } - else - { - Api.DeleteInstance(instanceName); - } + localDB.DeleteInstanceInternal(instanceName, throwIfNotFound: false, deleteFiles: DeleteFiles); + } + else + { + Api.DeleteInstance(instanceName); } } } diff --git a/src/TestApp/Program.cs b/src/TestApp/Program.cs index 663beef7..350711a2 100644 --- a/src/TestApp/Program.cs +++ b/src/TestApp/Program.cs @@ -8,183 +8,182 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -namespace MartinCostello.SqlLocalDb +namespace MartinCostello.SqlLocalDb; + +/// +/// An application that acts as a test harness for the MartinCostello.SqlLocalDb assembly. This class cannot be inherited. +/// +internal static class Program { /// - /// An application that acts as a test harness for the MartinCostello.SqlLocalDb assembly. This class cannot be inherited. + /// The main entry point to the application. /// - internal static class Program + /// The command-line arguments passed to the application. + /// + /// A representing the asynchronous application. + /// + internal static async Task Main(string[] args) { - /// - /// The main entry point to the application. - /// - /// The command-line arguments passed to the application. - /// - /// A representing the asynchronous application. - /// - internal static async Task Main(string[] args) + PrintBanner(); + + var options = new SqlLocalDbOptions() { - PrintBanner(); + AutomaticallyDeleteInstanceFiles = true, + StopOptions = StopInstanceOptions.NoWait, + }; - var options = new SqlLocalDbOptions() - { - AutomaticallyDeleteInstanceFiles = true, - StopOptions = StopInstanceOptions.NoWait, - }; + var services = new ServiceCollection().AddLogging((p) => p.AddConsole().SetMinimumLevel(LogLevel.Debug)); + var loggerFactory = services.BuildServiceProvider().GetRequiredService(); - var services = new ServiceCollection().AddLogging((p) => p.AddConsole().SetMinimumLevel(LogLevel.Debug)); - var loggerFactory = services.BuildServiceProvider().GetRequiredService(); + using (var localDB = new SqlLocalDbApi(options, loggerFactory)) + { + if (!localDB.IsLocalDBInstalled()) + { + Console.WriteLine(SR.SqlLocalDbApi_NotInstalledFormat, Environment.MachineName); + return; + } - using (var localDB = new SqlLocalDbApi(options, loggerFactory)) + if (args?.Length == 1 && + (string.Equals(args[0], "/deleteuserinstances", StringComparison.OrdinalIgnoreCase) || + string.Equals(args[0], "--delete-user-instances", StringComparison.OrdinalIgnoreCase))) { - if (!localDB.IsLocalDBInstalled()) - { - Console.WriteLine(SR.SqlLocalDbApi_NotInstalledFormat, Environment.MachineName); - return; - } + localDB.DeleteUserInstances(deleteFiles: true); + } - if (args?.Length == 1 && - (string.Equals(args[0], "/deleteuserinstances", StringComparison.OrdinalIgnoreCase) || - string.Equals(args[0], "--delete-user-instances", StringComparison.OrdinalIgnoreCase))) - { - localDB.DeleteUserInstances(deleteFiles: true); - } + IReadOnlyList versions = localDB.GetVersions(); - IReadOnlyList versions = localDB.GetVersions(); + Console.WriteLine(Strings.Program_VersionsListHeader); + Console.WriteLine(); - Console.WriteLine(Strings.Program_VersionsListHeader); - Console.WriteLine(); + foreach (ISqlLocalDbVersionInfo version in versions) + { + Console.WriteLine(version.Name); + } - foreach (ISqlLocalDbVersionInfo version in versions) - { - Console.WriteLine(version.Name); - } + Console.WriteLine(); - Console.WriteLine(); + IReadOnlyList instances = localDB.GetInstances(); - IReadOnlyList instances = localDB.GetInstances(); + Console.WriteLine(Strings.Program_InstancesListHeader); + Console.WriteLine(); - Console.WriteLine(Strings.Program_InstancesListHeader); - Console.WriteLine(); + foreach (ISqlLocalDbInstanceInfo instanceInfo in instances) + { + Console.WriteLine(instanceInfo.Name); + } - foreach (ISqlLocalDbInstanceInfo instanceInfo in instances) - { - Console.WriteLine(instanceInfo.Name); - } + Console.WriteLine(); - Console.WriteLine(); + string instanceName = Guid.NewGuid().ToString(); - string instanceName = Guid.NewGuid().ToString(); + ISqlLocalDbInstanceInfo instance = localDB.CreateInstance(instanceName); - ISqlLocalDbInstanceInfo instance = localDB.CreateInstance(instanceName); + var manager = new SqlLocalDbInstanceManager(instance, localDB); + manager.Start(); - var manager = new SqlLocalDbInstanceManager(instance, localDB); - manager.Start(); + try + { + if (IsCurrentUserAdmin()) + { + manager.Share(Guid.NewGuid().ToString()); + } try { - if (IsCurrentUserAdmin()) - { - manager.Share(Guid.NewGuid().ToString()); - } + using SqlConnection connection = manager.CreateConnection(); + await connection.OpenAsync(); try { - using SqlConnection connection = manager.CreateConnection(); - await connection.OpenAsync(); - - try - { - await ExecuteCommandAsync(connection, (command) => command.CommandText = "create database [MyDatabase]"); - await ExecuteCommandAsync(connection, (command) => command.CommandText = "drop database [MyDatabase]"); - } - finally - { - await connection.CloseAsync(); - } + await ExecuteCommandAsync(connection, (command) => command.CommandText = "create database [MyDatabase]"); + await ExecuteCommandAsync(connection, (command) => command.CommandText = "drop database [MyDatabase]"); } finally { - if (IsCurrentUserAdmin()) - { - manager.Unshare(); - } + await connection.CloseAsync(); } } -#pragma warning disable CA1031 - catch (Exception ex) - { - Console.WriteLine(ex.ToString()); - } -#pragma warning restore CA1031 finally { - manager.Stop(); - localDB.DeleteInstance(instance.Name); + if (IsCurrentUserAdmin()) + { + manager.Unshare(); + } } } - - Console.WriteLine(); - Console.Write(Strings.Program_ExitPrompt); - Console.ReadKey(); +#pragma warning disable CA1031 + catch (Exception ex) + { + Console.WriteLine(ex.ToString()); + } +#pragma warning restore CA1031 + finally + { + manager.Stop(); + localDB.DeleteInstance(instance.Name); + } } - private static async Task ExecuteCommandAsync(SqlConnection connection, Action configure) + Console.WriteLine(); + Console.Write(Strings.Program_ExitPrompt); + Console.ReadKey(); + } + + private static async Task ExecuteCommandAsync(SqlConnection connection, Action configure) + { + using SqlCommand command = new SqlCommand() { - using SqlCommand command = new SqlCommand() - { - Connection = connection, - }; + Connection = connection, + }; - configure(command); + configure(command); - await command.ExecuteNonQueryAsync(); - } + await command.ExecuteNonQueryAsync(); + } - /// - /// Returns whether the current user is in the administrators group on the local machine. - /// - /// - /// if the current user is in the administrators - /// group on the local machine; otherwise . - /// - private static bool IsCurrentUserAdmin() + /// + /// Returns whether the current user is in the administrators group on the local machine. + /// + /// + /// if the current user is in the administrators + /// group on the local machine; otherwise . + /// + private static bool IsCurrentUserAdmin() + { + if (!OperatingSystem.IsWindows()) { - if (!OperatingSystem.IsWindows()) - { - return false; - } + return false; + } - using WindowsIdentity identity = WindowsIdentity.GetCurrent(); + using WindowsIdentity identity = WindowsIdentity.GetCurrent(); - WindowsPrincipal principal = new WindowsPrincipal(identity); - return principal.IsInRole(WindowsBuiltInRole.Administrator); - } + WindowsPrincipal principal = new WindowsPrincipal(identity); + return principal.IsInRole(WindowsBuiltInRole.Administrator); + } - /// - /// Prints a banner to the console containing assembly and operating system information. - /// - private static void PrintBanner() - { - Assembly assembly = typeof(SqlLocalDbApi).Assembly; - AssemblyName assemblyName = assembly.GetName(); - - Console.WriteLine( - Strings.Program_BannerFormat, - assemblyName.Name, - assembly.GetCustomAttribute()?.Copyright, - assemblyName.Version, - assembly.GetCustomAttribute()?.Version, - assembly.GetCustomAttribute()?.InformationalVersion, - assembly.GetCustomAttribute()?.Configuration, - Environment.UserDomainName, - Environment.UserName, - IsCurrentUserAdmin(), - Environment.OSVersion, - RuntimeInformation.OSDescription, - RuntimeInformation.FrameworkDescription, - RuntimeInformation.OSArchitecture, - RuntimeInformation.ProcessArchitecture); - } + /// + /// Prints a banner to the console containing assembly and operating system information. + /// + private static void PrintBanner() + { + Assembly assembly = typeof(SqlLocalDbApi).Assembly; + AssemblyName assemblyName = assembly.GetName(); + + Console.WriteLine( + Strings.Program_BannerFormat, + assemblyName.Name, + assembly.GetCustomAttribute()?.Copyright, + assemblyName.Version, + assembly.GetCustomAttribute()?.Version, + assembly.GetCustomAttribute()?.InformationalVersion, + assembly.GetCustomAttribute()?.Configuration, + Environment.UserDomainName, + Environment.UserName, + IsCurrentUserAdmin(), + Environment.OSVersion, + RuntimeInformation.OSDescription, + RuntimeInformation.FrameworkDescription, + RuntimeInformation.OSArchitecture, + RuntimeInformation.ProcessArchitecture); } } diff --git a/tests/SqlLocalDb.Tests/DelayedMessageBus.cs b/tests/SqlLocalDb.Tests/DelayedMessageBus.cs index 2a088be7..b1cd0c3f 100644 --- a/tests/SqlLocalDb.Tests/DelayedMessageBus.cs +++ b/tests/SqlLocalDb.Tests/DelayedMessageBus.cs @@ -3,36 +3,35 @@ using Xunit.Sdk; -namespace MartinCostello.SqlLocalDb +namespace MartinCostello.SqlLocalDb; + +internal sealed class DelayedMessageBus : IMessageBus { - internal sealed class DelayedMessageBus : IMessageBus + private readonly IMessageBus _inner; + private readonly List _messages = new List(); + + internal DelayedMessageBus(IMessageBus inner) { - private readonly IMessageBus _inner; - private readonly List _messages = new List(); + _inner = inner; + } - internal DelayedMessageBus(IMessageBus inner) + public bool QueueMessage(IMessageSinkMessage message) + { + lock (_messages) { - _inner = inner; + _messages.Add(message); } - public bool QueueMessage(IMessageSinkMessage message) - { - lock (_messages) - { - _messages.Add(message); - } - - // No way to ask the inner bus if they want to cancel without sending them the message, so - // we just go ahead and continue always. - return true; - } + // No way to ask the inner bus if they want to cancel without sending them the message, so + // we just go ahead and continue always. + return true; + } - public void Dispose() + public void Dispose() + { + foreach (var message in _messages) { - foreach (var message in _messages) - { - _inner.QueueMessage(message); - } + _inner.QueueMessage(message); } } } diff --git a/tests/SqlLocalDb.Tests/EventIdsTests.cs b/tests/SqlLocalDb.Tests/EventIdsTests.cs index 02150804..5de26d81 100644 --- a/tests/SqlLocalDb.Tests/EventIdsTests.cs +++ b/tests/SqlLocalDb.Tests/EventIdsTests.cs @@ -4,80 +4,79 @@ using System.Reflection; using Microsoft.Extensions.Logging; -namespace MartinCostello.SqlLocalDb +namespace MartinCostello.SqlLocalDb; + +public static class EventIdsTests { - public static class EventIdsTests + [Theory] + [InlineData("NativeApiLoaded", 1)] + [InlineData("NativeApiLoadFailed", 2)] + [InlineData("NativeApiNotLoaded", 3)] + [InlineData("NativeApiVersionOverriddenByUser", 4)] + [InlineData("NativeApiVersionOverrideNotFound", 5)] + [InlineData("NoNativeApiFound", 6)] + [InlineData("NativeApiPathNotFound", 7)] + [InlineData("NativeFunctionNotFound", 8)] + [InlineData("NotInstalled", 9)] + [InlineData("CreatingInstance", 10)] + [InlineData("CreatingInstanceFailed", 11)] + [InlineData("CreatedInstance", 12)] + [InlineData("DeletingInstance", 13)] + [InlineData("DeletingInstanceFailed", 14)] + [InlineData("DeletingInstanceFailedAsCannotBeNotFound", 15)] + [InlineData("DeletingInstanceFailedAsInUse", 16)] + [InlineData("DeletedInstance", 17)] + [InlineData("DeletingInstanceFiles", 18)] + [InlineData("DeletingInstanceFilesFailed", 19)] + [InlineData("DeletedInstanceFiles", 20)] + [InlineData("GettingInstanceInfo", 21)] + [InlineData("GettingInstanceInfoFailed", 22)] + [InlineData("GotInstanceInfo", 23)] + [InlineData("GettingInstanceNames", 24)] + [InlineData("GettingInstanceNamesFailed", 25)] + [InlineData("GotInstanceNames", 26)] + [InlineData("GettingVersionInfo", 27)] + [InlineData("GettingVersionInfoFailed", 28)] + [InlineData("GotVersionInfo", 29)] + [InlineData("GettingVersions", 30)] + [InlineData("GettingVersionsFailed", 31)] + [InlineData("GotVersions", 32)] + [InlineData("InvalidLanguageId", 33)] + [InlineData("InvalidRegistryKey", 34)] + [InlineData("RegistryKeyNotFound", 35)] + [InlineData("StartingInstance", 36)] + [InlineData("StartingInstanceFailed", 37)] + [InlineData("StartedInstance", 38)] + [InlineData("StoppingInstance", 39)] + [InlineData("StoppingInstanceFailed", 40)] + [InlineData("StoppedInstance", 41)] + [InlineData("StartingTracing", 42)] + [InlineData("StartingTracingFailed", 43)] + [InlineData("StartedTracing", 44)] + [InlineData("StoppedTracing", 45)] + [InlineData("StoppingTracingFailed", 46)] + [InlineData("StoppingTracing", 47)] + [InlineData("StopTemporaryInstanceFailed", 48)] + [InlineData("SharingInstance", 49)] + [InlineData("SharingInstanceFailed", 50)] + [InlineData("SharedInstance", 51)] + [InlineData("UnsharingInstance", 52)] + [InlineData("UnsharingInstanceFailed", 53)] + [InlineData("UnsharedInstance", 54)] + [InlineData("NativeApiUnloaded", 55)] + [InlineData("GenericError", 56)] + public static void EventId_Name_And_Value_Is_Correct(string name, int expected) { - [Theory] - [InlineData("NativeApiLoaded", 1)] - [InlineData("NativeApiLoadFailed", 2)] - [InlineData("NativeApiNotLoaded", 3)] - [InlineData("NativeApiVersionOverriddenByUser", 4)] - [InlineData("NativeApiVersionOverrideNotFound", 5)] - [InlineData("NoNativeApiFound", 6)] - [InlineData("NativeApiPathNotFound", 7)] - [InlineData("NativeFunctionNotFound", 8)] - [InlineData("NotInstalled", 9)] - [InlineData("CreatingInstance", 10)] - [InlineData("CreatingInstanceFailed", 11)] - [InlineData("CreatedInstance", 12)] - [InlineData("DeletingInstance", 13)] - [InlineData("DeletingInstanceFailed", 14)] - [InlineData("DeletingInstanceFailedAsCannotBeNotFound", 15)] - [InlineData("DeletingInstanceFailedAsInUse", 16)] - [InlineData("DeletedInstance", 17)] - [InlineData("DeletingInstanceFiles", 18)] - [InlineData("DeletingInstanceFilesFailed", 19)] - [InlineData("DeletedInstanceFiles", 20)] - [InlineData("GettingInstanceInfo", 21)] - [InlineData("GettingInstanceInfoFailed", 22)] - [InlineData("GotInstanceInfo", 23)] - [InlineData("GettingInstanceNames", 24)] - [InlineData("GettingInstanceNamesFailed", 25)] - [InlineData("GotInstanceNames", 26)] - [InlineData("GettingVersionInfo", 27)] - [InlineData("GettingVersionInfoFailed", 28)] - [InlineData("GotVersionInfo", 29)] - [InlineData("GettingVersions", 30)] - [InlineData("GettingVersionsFailed", 31)] - [InlineData("GotVersions", 32)] - [InlineData("InvalidLanguageId", 33)] - [InlineData("InvalidRegistryKey", 34)] - [InlineData("RegistryKeyNotFound", 35)] - [InlineData("StartingInstance", 36)] - [InlineData("StartingInstanceFailed", 37)] - [InlineData("StartedInstance", 38)] - [InlineData("StoppingInstance", 39)] - [InlineData("StoppingInstanceFailed", 40)] - [InlineData("StoppedInstance", 41)] - [InlineData("StartingTracing", 42)] - [InlineData("StartingTracingFailed", 43)] - [InlineData("StartedTracing", 44)] - [InlineData("StoppedTracing", 45)] - [InlineData("StoppingTracingFailed", 46)] - [InlineData("StoppingTracing", 47)] - [InlineData("StopTemporaryInstanceFailed", 48)] - [InlineData("SharingInstance", 49)] - [InlineData("SharingInstanceFailed", 50)] - [InlineData("SharedInstance", 51)] - [InlineData("UnsharingInstance", 52)] - [InlineData("UnsharingInstanceFailed", 53)] - [InlineData("UnsharedInstance", 54)] - [InlineData("NativeApiUnloaded", 55)] - [InlineData("GenericError", 56)] - public static void EventId_Name_And_Value_Is_Correct(string name, int expected) - { - // Arrange - FieldInfo? field = typeof(EventIds).GetField(name, BindingFlags.NonPublic | BindingFlags.Static); + // Arrange + FieldInfo? field = typeof(EventIds).GetField(name, BindingFlags.NonPublic | BindingFlags.Static); - // Act - object? value = field!.GetValue(null); - EventId eventId = (EventId)value!; + // Act + object? value = field!.GetValue(null); + EventId eventId = (EventId)value!; - // Asset - eventId.ShouldNotBe(default); - eventId.Name.ShouldBe(name); - eventId.Id.ShouldBe(expected); - } + // Asset + eventId.ShouldNotBe(default); + eventId.Name.ShouldBe(name); + eventId.Id.ShouldBe(expected); } } diff --git a/tests/SqlLocalDb.Tests/Examples.cs b/tests/SqlLocalDb.Tests/Examples.cs index f854632b..0ea197f2 100644 --- a/tests/SqlLocalDb.Tests/Examples.cs +++ b/tests/SqlLocalDb.Tests/Examples.cs @@ -5,88 +5,87 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -namespace MartinCostello.SqlLocalDb +namespace MartinCostello.SqlLocalDb; + +/// +/// A class that contains examples for using MartinCostello.SqlLocalDb. +/// +public class Examples { - /// - /// A class that contains examples for using MartinCostello.SqlLocalDb. - /// - public class Examples + public Examples(ITestOutputHelper outputHelper) { - public Examples(ITestOutputHelper outputHelper) - { - OutputHelper = outputHelper; - } + OutputHelper = outputHelper; + } - private ITestOutputHelper OutputHelper { get; } + private ITestOutputHelper OutputHelper { get; } - [WindowsOnlyFact] - public async Task Create_A_Sql_LocalDB_Instance() + [WindowsOnlyFact] + public async Task Create_A_Sql_LocalDB_Instance() + { + using (var localDB = new SqlLocalDbApi(OutputHelper.ToLoggerFactory())) { - using (var localDB = new SqlLocalDbApi(OutputHelper.ToLoggerFactory())) - { - ISqlLocalDbInstanceInfo instance = localDB.GetOrCreateInstance("MyInstance"); - ISqlLocalDbInstanceManager manager = instance.Manage(); - - if (!instance.IsRunning) - { - manager.Start(); - } + ISqlLocalDbInstanceInfo instance = localDB.GetOrCreateInstance("MyInstance"); + ISqlLocalDbInstanceManager manager = instance.Manage(); - await using (SqlConnection connection = instance.CreateConnection()) - { - connection.Open(); + if (!instance.IsRunning) + { + manager.Start(); + } - // Use the SQL connection... - } + await using (SqlConnection connection = instance.CreateConnection()) + { + connection.Open(); - manager.Stop(); + // Use the SQL connection... } + + manager.Stop(); } + } - [WindowsOnlyFact] - public async Task Create_A_Temporary_Sql_LocalDB_Instance() + [WindowsOnlyFact] + public async Task Create_A_Temporary_Sql_LocalDB_Instance() + { + using (var localDB = new SqlLocalDbApi(OutputHelper.ToLoggerFactory())) { - using (var localDB = new SqlLocalDbApi(OutputHelper.ToLoggerFactory())) + using (TemporarySqlLocalDbInstance instance = localDB.CreateTemporaryInstance(deleteFiles: true)) { - using (TemporarySqlLocalDbInstance instance = localDB.CreateTemporaryInstance(deleteFiles: true)) + await using (var connection = new SqlConnection(instance.ConnectionString)) { - await using (var connection = new SqlConnection(instance.ConnectionString)) - { - connection.Open(); + connection.Open(); - // Use the SQL connection... - } + // Use the SQL connection... } } } + } - [WindowsOnlyFact] - public async Task Use_With_Dependency_Injection() - { - // Register with SQL LocalDB services - var services = new ServiceCollection() - .AddLogging((builder) => builder.AddXUnit(OutputHelper)) - .AddSqlLocalDB(); + [WindowsOnlyFact] + public async Task Use_With_Dependency_Injection() + { + // Register with SQL LocalDB services + var services = new ServiceCollection() + .AddLogging((builder) => builder.AddXUnit(OutputHelper)) + .AddSqlLocalDB(); - IServiceProvider serviceProvider = services.BuildServiceProvider(); + IServiceProvider serviceProvider = services.BuildServiceProvider(); - await using (AsyncServiceScope scope = serviceProvider.CreateAsyncScope()) - { - ISqlLocalDbApi localDB = scope!.ServiceProvider!.GetRequiredService(); - ISqlLocalDbInstanceInfo instance = localDB!.GetDefaultInstance(); - ISqlLocalDbInstanceManager manager = instance.Manage(); + await using (AsyncServiceScope scope = serviceProvider.CreateAsyncScope()) + { + ISqlLocalDbApi localDB = scope!.ServiceProvider!.GetRequiredService(); + ISqlLocalDbInstanceInfo instance = localDB!.GetDefaultInstance(); + ISqlLocalDbInstanceManager manager = instance.Manage(); - if (!instance.IsRunning) - { - manager.Start(); - } + if (!instance.IsRunning) + { + manager.Start(); + } - await using (SqlConnection connection = instance.CreateConnection()) - { - connection.Open(); + await using (SqlConnection connection = instance.CreateConnection()) + { + connection.Open(); - // Use the SQL connection... - } + // Use the SQL connection... } } } diff --git a/tests/SqlLocalDb.Tests/ISqlLocalDbApiExtensionsTests.cs b/tests/SqlLocalDb.Tests/ISqlLocalDbApiExtensionsTests.cs index 053cf6ba..0728146b 100644 --- a/tests/SqlLocalDb.Tests/ISqlLocalDbApiExtensionsTests.cs +++ b/tests/SqlLocalDb.Tests/ISqlLocalDbApiExtensionsTests.cs @@ -4,514 +4,513 @@ using Microsoft.Extensions.Logging; using Moq; -namespace MartinCostello.SqlLocalDb +namespace MartinCostello.SqlLocalDb; + +public class ISqlLocalDbApiExtensionsTests { - public class ISqlLocalDbApiExtensionsTests + private readonly ILoggerFactory _loggerFactory; + + public ISqlLocalDbApiExtensionsTests(ITestOutputHelper outputHelper) { - private readonly ILoggerFactory _loggerFactory; + _loggerFactory = outputHelper.ToLoggerFactory(); + } - public ISqlLocalDbApiExtensionsTests(ITestOutputHelper outputHelper) + [Theory] + [InlineData(unchecked((int)0x89c50112))] + [InlineData(unchecked((int)0x89c50108))] + public static void TemporaryInstance_Ignores_Exception_If_Delete_Fails(int errorCode) + { + // Arrange + if (!SqlLocalDbApi.IsWindows) { - _loggerFactory = outputHelper.ToLoggerFactory(); + // HACK Theories dont seem to work correctly with subclasses now + // so cannot make a derived class for a "Windows-only" theory. + return; } - [Theory] - [InlineData(unchecked((int)0x89c50112))] - [InlineData(unchecked((int)0x89c50108))] - public static void TemporaryInstance_Ignores_Exception_If_Delete_Fails(int errorCode) - { - // Arrange - if (!SqlLocalDbApi.IsWindows) - { - // HACK Theories dont seem to work correctly with subclasses now - // so cannot make a derived class for a "Windows-only" theory. - return; - } - - // Arrange - var mock = new Mock(); + // Arrange + var mock = new Mock(); - mock.Setup((p) => p.LatestVersion) - .Returns("v99.9"); + mock.Setup((p) => p.LatestVersion) + .Returns("v99.9"); - mock.Setup((p) => p.CreateInstance(It.IsAny(), "v99.9")) - .Verifiable(); + mock.Setup((p) => p.CreateInstance(It.IsAny(), "v99.9")) + .Verifiable(); - mock.Setup((p) => p.StartInstance(It.IsAny())) - .Verifiable(); + mock.Setup((p) => p.StartInstance(It.IsAny())) + .Verifiable(); - mock.Setup((p) => p.StopInstance(It.IsAny(), null)) - .Verifiable(); + mock.Setup((p) => p.StopInstance(It.IsAny(), null)) + .Verifiable(); - mock.Setup((p) => p.DeleteInstance(It.IsAny())) - .Throws(new SqlLocalDbException("Error", errorCode)) - .Verifiable(); + mock.Setup((p) => p.DeleteInstance(It.IsAny())) + .Throws(new SqlLocalDbException("Error", errorCode)) + .Verifiable(); - ISqlLocalDbApi api = mock.Object; - - // Act - using (TemporarySqlLocalDbInstance target = api.CreateTemporaryInstance()) - { - target.GetInstanceInfo(); - } - - // Assert - mock.Verify(); - } + ISqlLocalDbApi api = mock.Object; - [WindowsOnlyFact] - public static void ShareInstance_Uses_SID_For_Current_User() + // Act + using (TemporarySqlLocalDbInstance target = api.CreateTemporaryInstance()) { - // Arrange - string instanceName = "SomeName"; - string sharedInstanceName = "SomeSharedName"; + target.GetInstanceInfo(); + } - var mock = new Mock(); + // Assert + mock.Verify(); + } - mock.Setup((p) => p.ShareInstance(It.IsNotNull(), instanceName, sharedInstanceName)) - .Verifiable(); + [WindowsOnlyFact] + public static void ShareInstance_Uses_SID_For_Current_User() + { + // Arrange + string instanceName = "SomeName"; + string sharedInstanceName = "SomeSharedName"; - ISqlLocalDbApi api = mock.Object; + var mock = new Mock(); - // Act - api.ShareInstance(instanceName, sharedInstanceName); + mock.Setup((p) => p.ShareInstance(It.IsNotNull(), instanceName, sharedInstanceName)) + .Verifiable(); - // Assert - mock.Verify(); - } + ISqlLocalDbApi api = mock.Object; - [Fact] - public void CreateTemporaryInstance_Throws_If_Api_Is_Null() - { - // Arrange - ISqlLocalDbApi? api = null; + // Act + api.ShareInstance(instanceName, sharedInstanceName); - // Act and Assert - Assert.Throws("api", () => api!.CreateTemporaryInstance()); - } + // Assert + mock.Verify(); + } - [Fact] - public void TemporaryInstance_Throws_If_Used_After_Disposal() - { - // Arrange - var api = Mock.Of(); + [Fact] + public void CreateTemporaryInstance_Throws_If_Api_Is_Null() + { + // Arrange + ISqlLocalDbApi? api = null; - TemporarySqlLocalDbInstance instance = api.CreateTemporaryInstance(); + // Act and Assert + Assert.Throws("api", () => api!.CreateTemporaryInstance()); + } - // Act - instance.Dispose(); + [Fact] + public void TemporaryInstance_Throws_If_Used_After_Disposal() + { + // Arrange + var api = Mock.Of(); - // Assert - Assert.Throws(() => instance.Name); - Assert.Throws(() => instance.GetInstanceInfo()); - } + TemporarySqlLocalDbInstance instance = api.CreateTemporaryInstance(); - [Fact] - public void TemporaryInstance_Disposes_Cleanly_If_Not_Used() - { - // Arrange - var api = Mock.Of(); + // Act + instance.Dispose(); - // Act and Assert - using TemporarySqlLocalDbInstance instance = api.CreateTemporaryInstance(); - instance.Dispose(); - } + // Assert + Assert.Throws(() => instance.Name); + Assert.Throws(() => instance.GetInstanceInfo()); + } - [Fact] - public void TemporaryInstance_Is_ISqlLocalDbApiAdapter() - { - // Arrange - var api = Mock.Of(); + [Fact] + public void TemporaryInstance_Disposes_Cleanly_If_Not_Used() + { + // Arrange + var api = Mock.Of(); - using TemporarySqlLocalDbInstance instance = api.CreateTemporaryInstance(); + // Act and Assert + using TemporarySqlLocalDbInstance instance = api.CreateTemporaryInstance(); + instance.Dispose(); + } - // Act - ISqlLocalDbApiAdapter adapter = instance; + [Fact] + public void TemporaryInstance_Is_ISqlLocalDbApiAdapter() + { + // Arrange + var api = Mock.Of(); - // Assert - adapter.LocalDb.ShouldBeSameAs(api); - } + using TemporarySqlLocalDbInstance instance = api.CreateTemporaryInstance(); - [Fact] - public void TemporaryInstance_Deletes_Instance_If_Start_Fails() - { - // Arrange - var mock = new Mock(); + // Act + ISqlLocalDbApiAdapter adapter = instance; - mock.Setup((p) => p.LatestVersion) - .Returns("v99.9"); + // Assert + adapter.LocalDb.ShouldBeSameAs(api); + } - mock.Setup((p) => p.CreateInstance(It.IsAny(), "v99.9")) - .Verifiable(); + [Fact] + public void TemporaryInstance_Deletes_Instance_If_Start_Fails() + { + // Arrange + var mock = new Mock(); - mock.Setup((p) => p.StartInstance(It.IsAny())) - .Throws(); + mock.Setup((p) => p.LatestVersion) + .Returns("v99.9"); - mock.Setup((p) => p.DeleteInstance(It.IsAny())) - .Verifiable(); + mock.Setup((p) => p.CreateInstance(It.IsAny(), "v99.9")) + .Verifiable(); - ISqlLocalDbApi api = mock.Object; + mock.Setup((p) => p.StartInstance(It.IsAny())) + .Throws(); - using (TemporarySqlLocalDbInstance target = api.CreateTemporaryInstance()) - { - // Act and Assert - Assert.Throws(() => target.GetInstanceInfo()); - } + mock.Setup((p) => p.DeleteInstance(It.IsAny())) + .Verifiable(); - mock.Verify(); - } + ISqlLocalDbApi api = mock.Object; - [Theory] - [InlineData(unchecked((int)0x89c50108))] - [InlineData(unchecked((int)0x89c50107))] - public void TemporaryInstance_Ignores_Exception_If_Stop_Fails(int errorCode) + using (TemporarySqlLocalDbInstance target = api.CreateTemporaryInstance()) { - // Arrange - var mock = new Mock(); + // Act and Assert + Assert.Throws(() => target.GetInstanceInfo()); + } - mock.Setup((p) => p.LatestVersion) - .Returns("v99.9"); + mock.Verify(); + } - mock.Setup((p) => p.CreateInstance(It.IsAny(), "v99.9")) - .Verifiable(); + [Theory] + [InlineData(unchecked((int)0x89c50108))] + [InlineData(unchecked((int)0x89c50107))] + public void TemporaryInstance_Ignores_Exception_If_Stop_Fails(int errorCode) + { + // Arrange + var mock = new Mock(); - mock.Setup((p) => p.StartInstance(It.IsAny())) - .Verifiable(); + mock.Setup((p) => p.LatestVersion) + .Returns("v99.9"); - mock.Setup((p) => p.StopInstance(It.IsAny(), null)) - .Throws(new SqlLocalDbException("Error", errorCode)) - .Verifiable(); + mock.Setup((p) => p.CreateInstance(It.IsAny(), "v99.9")) + .Verifiable(); - mock.Setup((p) => p.DeleteInstance(It.IsAny())) - .Verifiable(); + mock.Setup((p) => p.StartInstance(It.IsAny())) + .Verifiable(); - ISqlLocalDbApi api = mock.Object; + mock.Setup((p) => p.StopInstance(It.IsAny(), null)) + .Throws(new SqlLocalDbException("Error", errorCode)) + .Verifiable(); - // Act - using (TemporarySqlLocalDbInstance target = api.CreateTemporaryInstance()) - { - target.GetInstanceInfo(); - } + mock.Setup((p) => p.DeleteInstance(It.IsAny())) + .Verifiable(); - // Assert - mock.Verify(); - } + ISqlLocalDbApi api = mock.Object; - [Fact] - public void GetDefaultInstance_Throws_If_Api_Is_Null() + // Act + using (TemporarySqlLocalDbInstance target = api.CreateTemporaryInstance()) { - // Arrange - ISqlLocalDbApi? api = null; - - // Act and Assert - Assert.Throws("api", () => api!.GetDefaultInstance()); + target.GetInstanceInfo(); } - [WindowsOnlyFact] - public void GetDefaultInstance_Returns_The_Default_Instance() - { - // Arrange - using var api = new SqlLocalDbApi(_loggerFactory); - - // Act - ISqlLocalDbInstanceInfo actual = api.GetDefaultInstance(); - - // Assert - actual.ShouldNotBeNull(); - actual.IsAutomatic.ShouldBeTrue(); - actual.Name.ShouldBe(api.DefaultInstanceName); - } - - [Fact] - public void GetInstances_Throws_If_Api_Is_Null() - { - // Arrange - ISqlLocalDbApi? api = null; - - // Act and Assert - Assert.Throws("api", () => api!.GetInstances()); - } + // Assert + mock.Verify(); + } - [WindowsOnlyFact] - public void GetInstances_Returns_All_The_Named_Instances() - { - // Arrange - using var api = new SqlLocalDbApi(_loggerFactory); + [Fact] + public void GetDefaultInstance_Throws_If_Api_Is_Null() + { + // Arrange + ISqlLocalDbApi? api = null; - // Act - IReadOnlyList actual = api.GetInstances(); + // Act and Assert + Assert.Throws("api", () => api!.GetDefaultInstance()); + } - // Assert - actual.ShouldNotBeNull(); - actual.Count.ShouldBeGreaterThanOrEqualTo(1); - actual.ShouldBeUnique(); - actual.ShouldAllBe((p) => p != null); - actual.ShouldContain((p) => p.Name == api.DefaultInstanceName); - actual.ShouldContain((p) => p.IsAutomatic); - } + [WindowsOnlyFact] + public void GetDefaultInstance_Returns_The_Default_Instance() + { + // Arrange + using var api = new SqlLocalDbApi(_loggerFactory); - [Fact] - public void GetInstances_Returns_Empty_If_No_Instances() - { - // Arrange - var api = Mock.Of(); + // Act + ISqlLocalDbInstanceInfo actual = api.GetDefaultInstance(); - // Act - IReadOnlyList actual = api.GetInstances(); + // Assert + actual.ShouldNotBeNull(); + actual.IsAutomatic.ShouldBeTrue(); + actual.Name.ShouldBe(api.DefaultInstanceName); + } - // Assert - actual.ShouldNotBeNull(); - actual.ShouldBeEmpty(); - } + [Fact] + public void GetInstances_Throws_If_Api_Is_Null() + { + // Arrange + ISqlLocalDbApi? api = null; - [Fact] - public void GetVersions_Throws_If_Api_Is_Null() - { - // Arrange - ISqlLocalDbApi? api = null; + // Act and Assert + Assert.Throws("api", () => api!.GetInstances()); + } - // Act and Assert - Assert.Throws("api", () => api!.GetVersions()); - } + [WindowsOnlyFact] + public void GetInstances_Returns_All_The_Named_Instances() + { + // Arrange + using var api = new SqlLocalDbApi(_loggerFactory); + + // Act + IReadOnlyList actual = api.GetInstances(); + + // Assert + actual.ShouldNotBeNull(); + actual.Count.ShouldBeGreaterThanOrEqualTo(1); + actual.ShouldBeUnique(); + actual.ShouldAllBe((p) => p != null); + actual.ShouldContain((p) => p.Name == api.DefaultInstanceName); + actual.ShouldContain((p) => p.IsAutomatic); + } - [WindowsOnlyFact] - public void GetVersions_Returns_All_The_Installed_Versions() - { - // Arrange - using var api = new SqlLocalDbApi(_loggerFactory); + [Fact] + public void GetInstances_Returns_Empty_If_No_Instances() + { + // Arrange + var api = Mock.Of(); - // Act - IReadOnlyList actual = api.GetVersions(); + // Act + IReadOnlyList actual = api.GetInstances(); - // Assert - actual.ShouldNotBeNull(); - actual.Count.ShouldBeGreaterThanOrEqualTo(1); - actual.ShouldBeUnique(); - actual.ShouldAllBe((p) => p != null); - actual.ShouldContain((p) => p.Exists); - } + // Assert + actual.ShouldNotBeNull(); + actual.ShouldBeEmpty(); + } - [Fact] - public void GetVersions_Returns_Empty_If_No_Versions() - { - // Arrange - var api = Mock.Of(); + [Fact] + public void GetVersions_Throws_If_Api_Is_Null() + { + // Arrange + ISqlLocalDbApi? api = null; - // Act - IReadOnlyList actual = api.GetVersions(); + // Act and Assert + Assert.Throws("api", () => api!.GetVersions()); + } - // Assert - actual.ShouldNotBeNull(); - actual.ShouldBeEmpty(); - } + [WindowsOnlyFact] + public void GetVersions_Returns_All_The_Installed_Versions() + { + // Arrange + using var api = new SqlLocalDbApi(_loggerFactory); + + // Act + IReadOnlyList actual = api.GetVersions(); + + // Assert + actual.ShouldNotBeNull(); + actual.Count.ShouldBeGreaterThanOrEqualTo(1); + actual.ShouldBeUnique(); + actual.ShouldAllBe((p) => p != null); + actual.ShouldContain((p) => p.Exists); + } - [Fact] - public void GetOrCreateInstance_Throws_If_Api_Is_Null() - { - // Arrange - ISqlLocalDbApi? api = null; - string instanceName = "SomeName"; + [Fact] + public void GetVersions_Returns_Empty_If_No_Versions() + { + // Arrange + var api = Mock.Of(); - // Act and Assert - Assert.Throws("api", () => api!.GetOrCreateInstance(instanceName)); - } + // Act + IReadOnlyList actual = api.GetVersions(); - [Fact] - public void GetOrCreateInstance_Throws_If_InstanceName_Is_Null() - { - // Arrange - ISqlLocalDbApi api = Mock.Of(); - string? instanceName = null; + // Assert + actual.ShouldNotBeNull(); + actual.ShouldBeEmpty(); + } - // Act and Assert - Assert.Throws("instanceName", () => api.GetOrCreateInstance(instanceName!)); - } + [Fact] + public void GetOrCreateInstance_Throws_If_Api_Is_Null() + { + // Arrange + ISqlLocalDbApi? api = null; + string instanceName = "SomeName"; - [Fact] - public void GetOrCreateInstance_Returns_The_Default_Instance_If_It_Exists_With_The_Default_Name() - { - // Arrange - string instanceName = "Default"; + // Act and Assert + Assert.Throws("api", () => api!.GetOrCreateInstance(instanceName)); + } - var mock = new Mock(); + [Fact] + public void GetOrCreateInstance_Throws_If_InstanceName_Is_Null() + { + // Arrange + ISqlLocalDbApi api = Mock.Of(); + string? instanceName = null; - mock.Setup((p) => p.DefaultInstanceName) - .Returns(instanceName); + // Act and Assert + Assert.Throws("instanceName", () => api.GetOrCreateInstance(instanceName!)); + } - mock.Setup((p) => p.GetInstanceInfo(instanceName)) - .Returns(CreateInstanceInfo(exists: true)); + [Fact] + public void GetOrCreateInstance_Returns_The_Default_Instance_If_It_Exists_With_The_Default_Name() + { + // Arrange + string instanceName = "Default"; - ISqlLocalDbApi api = mock.Object; + var mock = new Mock(); - // Act - ISqlLocalDbInstanceInfo actual = api.GetOrCreateInstance(instanceName); + mock.Setup((p) => p.DefaultInstanceName) + .Returns(instanceName); - // Assert - actual.ShouldNotBeNull(); - actual.Exists.ShouldBeTrue(); - } + mock.Setup((p) => p.GetInstanceInfo(instanceName)) + .Returns(CreateInstanceInfo(exists: true)); - [Theory] - [InlineData("v11.0")] - [InlineData("MSSQLLocalDB")] - public void GetOrCreateInstance_Returns_The_Default_Instance_If_It_Exists(string instanceName) - { - // Arrange - var mock = new Mock(); + ISqlLocalDbApi api = mock.Object; - mock.Setup((p) => p.DefaultInstanceName) - .Returns("Blah"); + // Act + ISqlLocalDbInstanceInfo actual = api.GetOrCreateInstance(instanceName); - mock.Setup((p) => p.GetInstanceInfo(instanceName)) - .Returns(CreateInstanceInfo(exists: true)); + // Assert + actual.ShouldNotBeNull(); + actual.Exists.ShouldBeTrue(); + } - ISqlLocalDbApi api = mock.Object; + [Theory] + [InlineData("v11.0")] + [InlineData("MSSQLLocalDB")] + public void GetOrCreateInstance_Returns_The_Default_Instance_If_It_Exists(string instanceName) + { + // Arrange + var mock = new Mock(); - // Act - ISqlLocalDbInstanceInfo actual = api.GetOrCreateInstance(instanceName); + mock.Setup((p) => p.DefaultInstanceName) + .Returns("Blah"); - // Assert - actual.ShouldNotBeNull(); - actual.Exists.ShouldBeTrue(); - } + mock.Setup((p) => p.GetInstanceInfo(instanceName)) + .Returns(CreateInstanceInfo(exists: true)); - [Fact] - public void GetOrCreateInstance_Returns_An_Instance_If_It_Exists() - { - // Arrange - string instanceName = "MyInstance"; + ISqlLocalDbApi api = mock.Object; - var mock = new Mock(); + // Act + ISqlLocalDbInstanceInfo actual = api.GetOrCreateInstance(instanceName); - mock.Setup((p) => p.DefaultInstanceName) - .Returns("Blah"); + // Assert + actual.ShouldNotBeNull(); + actual.Exists.ShouldBeTrue(); + } - mock.Setup((p) => p.InstanceExists(instanceName)) - .Returns(true); + [Fact] + public void GetOrCreateInstance_Returns_An_Instance_If_It_Exists() + { + // Arrange + string instanceName = "MyInstance"; - mock.Setup((p) => p.GetInstanceInfo(instanceName)) - .Returns(CreateInstanceInfo(exists: true)); + var mock = new Mock(); - ISqlLocalDbApi api = mock.Object; + mock.Setup((p) => p.DefaultInstanceName) + .Returns("Blah"); - // Act - ISqlLocalDbInstanceInfo actual = api.GetOrCreateInstance(instanceName); + mock.Setup((p) => p.InstanceExists(instanceName)) + .Returns(true); - // Assert - actual.ShouldNotBeNull(); - } + mock.Setup((p) => p.GetInstanceInfo(instanceName)) + .Returns(CreateInstanceInfo(exists: true)); - [Fact] - public void GetOrCreateInstance_Returns_An_Instance_If_It_Does_Not_Exist() - { - // Arrange - string instanceName = "MyInstance"; + ISqlLocalDbApi api = mock.Object; - var mock = new Mock(); + // Act + ISqlLocalDbInstanceInfo actual = api.GetOrCreateInstance(instanceName); - mock.Setup((p) => p.DefaultInstanceName) - .Returns("Blah"); + // Assert + actual.ShouldNotBeNull(); + } - mock.Setup((p) => p.LatestVersion) - .Returns("v99.0"); + [Fact] + public void GetOrCreateInstance_Returns_An_Instance_If_It_Does_Not_Exist() + { + // Arrange + string instanceName = "MyInstance"; - mock.Setup((p) => p.CreateInstance(instanceName, "v99.0")) - .Returns(CreateInstanceInfo(exists: false)); + var mock = new Mock(); - ISqlLocalDbApi api = mock.Object; + mock.Setup((p) => p.DefaultInstanceName) + .Returns("Blah"); - // Act - ISqlLocalDbInstanceInfo actual = api.GetOrCreateInstance(instanceName); + mock.Setup((p) => p.LatestVersion) + .Returns("v99.0"); - // Assert - actual.ShouldNotBeNull(); - } + mock.Setup((p) => p.CreateInstance(instanceName, "v99.0")) + .Returns(CreateInstanceInfo(exists: false)); - [Fact] - public void ShareInstance_Throws_If_Api_Is_Null() - { - // Arrange - ISqlLocalDbApi? api = null; - string instanceName = "SomeName"; - string sharedInstanceName = "SomeSharedName"; + ISqlLocalDbApi api = mock.Object; - // Act and Assert - Assert.Throws("api", () => api!.ShareInstance(instanceName, sharedInstanceName)); - } + // Act + ISqlLocalDbInstanceInfo actual = api.GetOrCreateInstance(instanceName); - [WindowsOnlyFact] - public void CreateTemporaryInstance_Creates_Starts_And_Deletes_An_Instance_If_Files_Not_Deleted() - { - CreateTemporaryInstance_Creates_Starts_And_Deletes_An_Instance(deleteFiles: false); - } + // Assert + actual.ShouldNotBeNull(); + } - [WindowsOnlyFact] - public void CreateTemporaryInstance_Creates_Starts_And_Deletes_An_Instance_If_Files_Deleted() - { - CreateTemporaryInstance_Creates_Starts_And_Deletes_An_Instance(deleteFiles: true); - } + [Fact] + public void ShareInstance_Throws_If_Api_Is_Null() + { + // Arrange + ISqlLocalDbApi? api = null; + string instanceName = "SomeName"; + string sharedInstanceName = "SomeSharedName"; - [RunAsAdminFact] - public void ShareInstance_Shares_Instance_For_Current_User() - { - // Arrange - using var api = new SqlLocalDbApi(_loggerFactory); - using TemporarySqlLocalDbInstance target = api.CreateTemporaryInstance(deleteFiles: true); + // Act and Assert + Assert.Throws("api", () => api!.ShareInstance(instanceName, sharedInstanceName)); + } - target.GetInstanceInfo().IsShared.ShouldBeFalse(); + [WindowsOnlyFact] + public void CreateTemporaryInstance_Creates_Starts_And_Deletes_An_Instance_If_Files_Not_Deleted() + { + CreateTemporaryInstance_Creates_Starts_And_Deletes_An_Instance(deleteFiles: false); + } - // Act - api.ShareInstance(target.Name, Guid.NewGuid().ToString()); + [WindowsOnlyFact] + public void CreateTemporaryInstance_Creates_Starts_And_Deletes_An_Instance_If_Files_Deleted() + { + CreateTemporaryInstance_Creates_Starts_And_Deletes_An_Instance(deleteFiles: true); + } - // Assert - target.GetInstanceInfo().IsShared.ShouldBeTrue(); - } + [RunAsAdminFact] + public void ShareInstance_Shares_Instance_For_Current_User() + { + // Arrange + using var api = new SqlLocalDbApi(_loggerFactory); + using TemporarySqlLocalDbInstance target = api.CreateTemporaryInstance(deleteFiles: true); - private static ISqlLocalDbInstanceInfo CreateInstanceInfo(bool exists) - { - var mock = new Mock(); + target.GetInstanceInfo().IsShared.ShouldBeFalse(); - mock.Setup((p) => p.Exists).Returns(exists); + // Act + api.ShareInstance(target.Name, Guid.NewGuid().ToString()); - return mock.Object; - } + // Assert + target.GetInstanceInfo().IsShared.ShouldBeTrue(); + } - private void CreateTemporaryInstance_Creates_Starts_And_Deletes_An_Instance(bool deleteFiles) - { - // Arrange - using var api = new SqlLocalDbApi(_loggerFactory); + private static ISqlLocalDbInstanceInfo CreateInstanceInfo(bool exists) + { + var mock = new Mock(); - ISqlLocalDbInstanceInfo info; - string name; + mock.Setup((p) => p.Exists).Returns(exists); - // Act - using (TemporarySqlLocalDbInstance target = api.CreateTemporaryInstance(deleteFiles)) - { - // Assert - target.ShouldNotBeNull(); - target.Name.ShouldNotBeNull(); - target.Name.ShouldNotBeEmpty(); + return mock.Object; + } - Guid.TryParse(target.Name, out Guid nameAsGuid).ShouldBeTrue(); - nameAsGuid.ShouldNotBe(Guid.Empty); + private void CreateTemporaryInstance_Creates_Starts_And_Deletes_An_Instance(bool deleteFiles) + { + // Arrange + using var api = new SqlLocalDbApi(_loggerFactory); - // Act - info = target.GetInstanceInfo(); + ISqlLocalDbInstanceInfo info; + string name; - // Assert - info.ShouldNotBeNull(); - info.Exists.ShouldBeTrue(); - info.IsRunning.ShouldBeTrue(); + // Act + using (TemporarySqlLocalDbInstance target = api.CreateTemporaryInstance(deleteFiles)) + { + // Assert + target.ShouldNotBeNull(); + target.Name.ShouldNotBeNull(); + target.Name.ShouldNotBeEmpty(); - name = target.Name; - } + Guid.TryParse(target.Name, out Guid nameAsGuid).ShouldBeTrue(); + nameAsGuid.ShouldNotBe(Guid.Empty); // Act - info = api.GetInstanceInfo(name); + info = target.GetInstanceInfo(); // Assert info.ShouldNotBeNull(); - info.Exists.ShouldBeFalse(); + info.Exists.ShouldBeTrue(); + info.IsRunning.ShouldBeTrue(); + + name = target.Name; } + + // Act + info = api.GetInstanceInfo(name); + + // Assert + info.ShouldNotBeNull(); + info.Exists.ShouldBeFalse(); } } diff --git a/tests/SqlLocalDb.Tests/ISqlLocalDbInstanceInfoExtensionsTests.cs b/tests/SqlLocalDb.Tests/ISqlLocalDbInstanceInfoExtensionsTests.cs index 53dd3bf3..acbcbba6 100644 --- a/tests/SqlLocalDb.Tests/ISqlLocalDbInstanceInfoExtensionsTests.cs +++ b/tests/SqlLocalDb.Tests/ISqlLocalDbInstanceInfoExtensionsTests.cs @@ -4,126 +4,125 @@ using Microsoft.Data.SqlClient; using Moq; -namespace MartinCostello.SqlLocalDb +namespace MartinCostello.SqlLocalDb; + +public static class ISqlLocalDbInstanceInfoExtensionsTests { - public static class ISqlLocalDbInstanceInfoExtensionsTests + [Fact] + public static void CreateConnection_Throws_If_Instance_Is_Null() + { + // Arrange + ISqlLocalDbInstanceInfo? instance = null; + + // Act and Assert + Assert.Throws("instance", () => instance!.CreateConnection()); + } + + [Fact] + public static void CreateConnectionStringBuilder_Throws_If_Instance_Is_Null() + { + // Arrange + ISqlLocalDbInstanceInfo? instance = null; + + // Act and Assert + Assert.Throws("instance", () => instance!.CreateConnectionStringBuilder()); + } + + [Fact] + public static void CreateConnectionStringBuilder_Throws_If_The_Instance_Is_Not_Running() + { + // Arrange + var mock = new Mock(); + + mock.Setup((p) => p.IsRunning).Returns(false); + mock.Setup((p) => p.Name).Returns("MyInstance"); + mock.Setup((p) => p.NamedPipe).Returns("MyNamedPipe"); + + ISqlLocalDbInstanceInfo instance = mock.Object; + + // Act and Assert + var exception = Assert.Throws(() => instance.CreateConnectionStringBuilder()); + exception.Message.ShouldBe("The SQL LocalDB instance 'MyInstance' is not running."); + } + + [Fact] + public static void CreateConnectionStringBuilder_Initializes_Connection_String_Builder() + { + // Arrange + var mock = new Mock(); + + mock.Setup((p) => p.IsRunning).Returns(true); + mock.Setup((p) => p.NamedPipe).Returns("MyNamedPipe"); + + ISqlLocalDbInstanceInfo instance = mock.Object; + + // Act + SqlConnectionStringBuilder actual = instance.CreateConnectionStringBuilder(); + + // Assert + actual.ShouldNotBeNull(); + actual.DataSource.ShouldBe("MyNamedPipe"); + } + + [Fact] + public static void GetConnectionString_Returns_Sql_Connection_String() + { + // Arrange + var mock = new Mock(); + + mock.Setup((p) => p.IsRunning).Returns(true); + mock.Setup((p) => p.NamedPipe).Returns("MyNamedPipe"); + + ISqlLocalDbInstanceInfo instance = mock.Object; + + // Act + string actual = instance.GetConnectionString(); + + // Assert + actual.ShouldBe("Data Source=MyNamedPipe"); + } + + [Fact] + public static void Manage_Throws_If_Instance_Is_Null() { - [Fact] - public static void CreateConnection_Throws_If_Instance_Is_Null() - { - // Arrange - ISqlLocalDbInstanceInfo? instance = null; - - // Act and Assert - Assert.Throws("instance", () => instance!.CreateConnection()); - } - - [Fact] - public static void CreateConnectionStringBuilder_Throws_If_Instance_Is_Null() - { - // Arrange - ISqlLocalDbInstanceInfo? instance = null; - - // Act and Assert - Assert.Throws("instance", () => instance!.CreateConnectionStringBuilder()); - } - - [Fact] - public static void CreateConnectionStringBuilder_Throws_If_The_Instance_Is_Not_Running() - { - // Arrange - var mock = new Mock(); - - mock.Setup((p) => p.IsRunning).Returns(false); - mock.Setup((p) => p.Name).Returns("MyInstance"); - mock.Setup((p) => p.NamedPipe).Returns("MyNamedPipe"); - - ISqlLocalDbInstanceInfo instance = mock.Object; - - // Act and Assert - var exception = Assert.Throws(() => instance.CreateConnectionStringBuilder()); - exception.Message.ShouldBe("The SQL LocalDB instance 'MyInstance' is not running."); - } - - [Fact] - public static void CreateConnectionStringBuilder_Initializes_Connection_String_Builder() - { - // Arrange - var mock = new Mock(); - - mock.Setup((p) => p.IsRunning).Returns(true); - mock.Setup((p) => p.NamedPipe).Returns("MyNamedPipe"); - - ISqlLocalDbInstanceInfo instance = mock.Object; - - // Act - SqlConnectionStringBuilder actual = instance.CreateConnectionStringBuilder(); - - // Assert - actual.ShouldNotBeNull(); - actual.DataSource.ShouldBe("MyNamedPipe"); - } - - [Fact] - public static void GetConnectionString_Returns_Sql_Connection_String() - { - // Arrange - var mock = new Mock(); - - mock.Setup((p) => p.IsRunning).Returns(true); - mock.Setup((p) => p.NamedPipe).Returns("MyNamedPipe"); - - ISqlLocalDbInstanceInfo instance = mock.Object; - - // Act - string actual = instance.GetConnectionString(); - - // Assert - actual.ShouldBe("Data Source=MyNamedPipe"); - } - - [Fact] - public static void Manage_Throws_If_Instance_Is_Null() - { - // Arrange - ISqlLocalDbInstanceInfo? instance = null; - - // Act and Assert - Assert.Throws("instance", () => instance!.Manage()); - } - - [Fact] - public static void Manage_Throws_If_Instance_Does_Not_Implement_ISqlLocalDbApiAdapter() - { - // Arrange - var instance = Mock.Of(); - - // Act and Assert - Assert.Throws("instance", () => instance.Manage()).Message.ShouldStartWith("The specified instance of ISqlLocalDbInstanceInfo does not implement the ISqlLocalDbApiAdapter interface."); - } - - [Fact] - public static void Manage_Returns_An_ISqlLocalDbInstanceManager() - { - // Arrange - var api = Mock.Of(); - var mock = new Mock(); - - mock.As() - .Setup((p) => p.LocalDb).Returns(api); + // Arrange + ISqlLocalDbInstanceInfo? instance = null; + + // Act and Assert + Assert.Throws("instance", () => instance!.Manage()); + } + + [Fact] + public static void Manage_Throws_If_Instance_Does_Not_Implement_ISqlLocalDbApiAdapter() + { + // Arrange + var instance = Mock.Of(); + + // Act and Assert + Assert.Throws("instance", () => instance.Manage()).Message.ShouldStartWith("The specified instance of ISqlLocalDbInstanceInfo does not implement the ISqlLocalDbApiAdapter interface."); + } + + [Fact] + public static void Manage_Returns_An_ISqlLocalDbInstanceManager() + { + // Arrange + var api = Mock.Of(); + var mock = new Mock(); + + mock.As() + .Setup((p) => p.LocalDb).Returns(api); - ISqlLocalDbInstanceInfo instance = mock.Object; + ISqlLocalDbInstanceInfo instance = mock.Object; - // Act - ISqlLocalDbInstanceManager actual = instance.Manage(); + // Act + ISqlLocalDbInstanceManager actual = instance.Manage(); - // Assert - actual.ShouldNotBeNull(); + // Assert + actual.ShouldNotBeNull(); - var adapter = actual as ISqlLocalDbApiAdapter; + var adapter = actual as ISqlLocalDbApiAdapter; - adapter.ShouldNotBeNull(); - adapter!.LocalDb.ShouldBeSameAs(api); - } + adapter.ShouldNotBeNull(); + adapter!.LocalDb.ShouldBeSameAs(api); } } diff --git a/tests/SqlLocalDb.Tests/ISqlLocalDbInstanceManagerExtensionsTests.cs b/tests/SqlLocalDb.Tests/ISqlLocalDbInstanceManagerExtensionsTests.cs index caf741d7..ab635bf6 100644 --- a/tests/SqlLocalDb.Tests/ISqlLocalDbInstanceManagerExtensionsTests.cs +++ b/tests/SqlLocalDb.Tests/ISqlLocalDbInstanceManagerExtensionsTests.cs @@ -5,75 +5,74 @@ using Microsoft.Data.SqlClient; using Microsoft.Extensions.Logging; -namespace MartinCostello.SqlLocalDb +namespace MartinCostello.SqlLocalDb; + +public class ISqlLocalDbInstanceManagerExtensionsTests { - public class ISqlLocalDbInstanceManagerExtensionsTests + private readonly ILoggerFactory _loggerFactory; + + public ISqlLocalDbInstanceManagerExtensionsTests(ITestOutputHelper outputHelper) + { + _loggerFactory = outputHelper.ToLoggerFactory(); + } + + [Fact] + public void CreateConnection_Throws_If_Manager_Is_Null() + { + // Arrange + ISqlLocalDbInstanceManager? manager = null; + + // Act and Assert + Assert.Throws("manager", () => manager!.CreateConnection()); + } + + [WindowsOnlyFact] + public async Task CreateConnection_Creates_A_Sql_Connection() + { + // Arrange + using var api = new SqlLocalDbApi(_loggerFactory); + using TemporarySqlLocalDbInstance temporary = api.CreateTemporaryInstance(deleteFiles: true); + + ISqlLocalDbInstanceManager manager = temporary.Manage(); + + manager.ShouldNotBeNull(); + manager.Name.ShouldBe(temporary.Name); + + // Act + using SqlConnection actual = manager.CreateConnection(); + + // Assert + actual.ShouldNotBeNull(); + actual.ConnectionString.ShouldNotBeNull(); + actual.State.ShouldBe(ConnectionState.Closed); + + await actual.OpenAsync(); + actual.Close(); + } + + [Fact] + public void Restart_Throws_If_Manager_Is_Null() + { + // Arrange + ISqlLocalDbInstanceManager? manager = null; + + // Act and Assert + Assert.Throws("manager", () => manager!.Restart()); + } + + [WindowsOnlyFact] + public void Restart_Stops_And_Starts_Instance() { - private readonly ILoggerFactory _loggerFactory; - - public ISqlLocalDbInstanceManagerExtensionsTests(ITestOutputHelper outputHelper) - { - _loggerFactory = outputHelper.ToLoggerFactory(); - } - - [Fact] - public void CreateConnection_Throws_If_Manager_Is_Null() - { - // Arrange - ISqlLocalDbInstanceManager? manager = null; - - // Act and Assert - Assert.Throws("manager", () => manager!.CreateConnection()); - } - - [WindowsOnlyFact] - public async Task CreateConnection_Creates_A_Sql_Connection() - { - // Arrange - using var api = new SqlLocalDbApi(_loggerFactory); - using TemporarySqlLocalDbInstance temporary = api.CreateTemporaryInstance(deleteFiles: true); - - ISqlLocalDbInstanceManager manager = temporary.Manage(); - - manager.ShouldNotBeNull(); - manager.Name.ShouldBe(temporary.Name); - - // Act - using SqlConnection actual = manager.CreateConnection(); - - // Assert - actual.ShouldNotBeNull(); - actual.ConnectionString.ShouldNotBeNull(); - actual.State.ShouldBe(ConnectionState.Closed); - - await actual.OpenAsync(); - actual.Close(); - } - - [Fact] - public void Restart_Throws_If_Manager_Is_Null() - { - // Arrange - ISqlLocalDbInstanceManager? manager = null; - - // Act and Assert - Assert.Throws("manager", () => manager!.Restart()); - } - - [WindowsOnlyFact] - public void Restart_Stops_And_Starts_Instance() - { - // Arrange - using var api = new SqlLocalDbApi(_loggerFactory); - using TemporarySqlLocalDbInstance temporary = api.CreateTemporaryInstance(deleteFiles: true); - - ISqlLocalDbInstanceManager manager = temporary.Manage(); - - // Act - manager.Restart(); - - // Assert - temporary.GetInstanceInfo().IsRunning.ShouldBeTrue(); - } + // Arrange + using var api = new SqlLocalDbApi(_loggerFactory); + using TemporarySqlLocalDbInstance temporary = api.CreateTemporaryInstance(deleteFiles: true); + + ISqlLocalDbInstanceManager manager = temporary.Manage(); + + // Act + manager.Restart(); + + // Assert + temporary.GetInstanceInfo().IsRunning.ShouldBeTrue(); } } diff --git a/tests/SqlLocalDb.Tests/NotInParallelTests.cs b/tests/SqlLocalDb.Tests/NotInParallelTests.cs index 7d91a9b7..dcdd6263 100644 --- a/tests/SqlLocalDb.Tests/NotInParallelTests.cs +++ b/tests/SqlLocalDb.Tests/NotInParallelTests.cs @@ -3,50 +3,49 @@ using Microsoft.Extensions.Logging; -namespace MartinCostello.SqlLocalDb +namespace MartinCostello.SqlLocalDb; + +/// +/// A class containing tests that perform global operations that may cause other tests to fail if run in parallel. +/// +[CollectionDefinition("NotInParallel", DisableParallelization = true)] +public class NotInParallelTests { - /// - /// A class containing tests that perform global operations that may cause other tests to fail if run in parallel. - /// - [CollectionDefinition("NotInParallel", DisableParallelization = true)] - public class NotInParallelTests - { - private readonly ILoggerFactory _loggerFactory; + private readonly ILoggerFactory _loggerFactory; - public NotInParallelTests(ITestOutputHelper outputHelper) - { - _loggerFactory = outputHelper.ToLoggerFactory(); - } + public NotInParallelTests(ITestOutputHelper outputHelper) + { + _loggerFactory = outputHelper.ToLoggerFactory(); + } - [WindowsCIOnlyFact] - public void Can_Delete_User_Instances() + [WindowsCIOnlyFact] + public void Can_Delete_User_Instances() + { + // Arrange + using (var actual = new SqlLocalDbApi(_loggerFactory)) { - // Arrange - using (var actual = new SqlLocalDbApi(_loggerFactory)) - { - actual.CreateInstance(Guid.NewGuid().ToString()); + actual.CreateInstance(Guid.NewGuid().ToString()); - IReadOnlyList namesBefore = actual.GetInstanceNames(); + IReadOnlyList namesBefore = actual.GetInstanceNames(); - // Act - int deleted = actual.DeleteUserInstances(deleteFiles: true); + // Act + int deleted = actual.DeleteUserInstances(deleteFiles: true); - // Assert - deleted.ShouldBeGreaterThanOrEqualTo(1); - IReadOnlyList namesAfter = actual.GetInstanceNames(); + // Assert + deleted.ShouldBeGreaterThanOrEqualTo(1); + IReadOnlyList namesAfter = actual.GetInstanceNames(); - int instancesDeleted = 0; + int instancesDeleted = 0; - foreach (string name in namesBefore) + foreach (string name in namesBefore) + { + if (!namesAfter.Contains(name)) { - if (!namesAfter.Contains(name)) - { - instancesDeleted++; - } + instancesDeleted++; } - - instancesDeleted.ShouldBeGreaterThanOrEqualTo(1); } + + instancesDeleted.ShouldBeGreaterThanOrEqualTo(1); } } } diff --git a/tests/SqlLocalDb.Tests/NotWindowsFactAttribute.cs b/tests/SqlLocalDb.Tests/NotWindowsFactAttribute.cs index 427abe6a..9ebfdc90 100644 --- a/tests/SqlLocalDb.Tests/NotWindowsFactAttribute.cs +++ b/tests/SqlLocalDb.Tests/NotWindowsFactAttribute.cs @@ -1,19 +1,18 @@ // Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -namespace MartinCostello.SqlLocalDb +namespace MartinCostello.SqlLocalDb; + +/// +/// Attribute that is applied to a method to indicate that it is a fact that should be run by the +/// test runner if the current operating system is not Windows. This class cannot be inherited. +/// +[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] +public sealed class NotWindowsFactAttribute : FactAttribute { - /// - /// Attribute that is applied to a method to indicate that it is a fact that should be run by the - /// test runner if the current operating system is not Windows. This class cannot be inherited. - /// - [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] - public sealed class NotWindowsFactAttribute : FactAttribute + public NotWindowsFactAttribute() + : base() { - public NotWindowsFactAttribute() - : base() - { - Skip = !OperatingSystem.IsWindows() ? string.Empty : "This test can only be run on Windows."; - } + Skip = !OperatingSystem.IsWindows() ? string.Empty : "This test can only be run on Windows."; } } diff --git a/tests/SqlLocalDb.Tests/RetryFactDiscoverer.cs b/tests/SqlLocalDb.Tests/RetryFactDiscoverer.cs index bee0af15..297709f9 100644 --- a/tests/SqlLocalDb.Tests/RetryFactDiscoverer.cs +++ b/tests/SqlLocalDb.Tests/RetryFactDiscoverer.cs @@ -3,32 +3,31 @@ using Xunit.Sdk; -namespace MartinCostello.SqlLocalDb +namespace MartinCostello.SqlLocalDb; + +public sealed class RetryFactDiscoverer : IXunitTestCaseDiscoverer { - public sealed class RetryFactDiscoverer : IXunitTestCaseDiscoverer + private readonly IMessageSink _sink; + + public RetryFactDiscoverer(IMessageSink diagnosticMessageSink) { - private readonly IMessageSink _sink; + _sink = diagnosticMessageSink; + } - public RetryFactDiscoverer(IMessageSink diagnosticMessageSink) - { - _sink = diagnosticMessageSink; - } + public IEnumerable Discover(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IAttributeInfo factAttribute) + { + int maxRetries = factAttribute.GetNamedArgument("MaxRetries"); - public IEnumerable Discover(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IAttributeInfo factAttribute) + if (maxRetries < 1) { - int maxRetries = factAttribute.GetNamedArgument("MaxRetries"); - - if (maxRetries < 1) - { - maxRetries = 3; - } - - yield return new RetryTestCase( - _sink, - discoveryOptions.MethodDisplayOrDefault(), - discoveryOptions.MethodDisplayOptionsOrDefault(), - testMethod, - maxRetries); + maxRetries = 3; } + + yield return new RetryTestCase( + _sink, + discoveryOptions.MethodDisplayOrDefault(), + discoveryOptions.MethodDisplayOptionsOrDefault(), + testMethod, + maxRetries); } } diff --git a/tests/SqlLocalDb.Tests/RetryTestCase.cs b/tests/SqlLocalDb.Tests/RetryTestCase.cs index b9fc5ece..ebc5fe4b 100644 --- a/tests/SqlLocalDb.Tests/RetryTestCase.cs +++ b/tests/SqlLocalDb.Tests/RetryTestCase.cs @@ -4,69 +4,68 @@ using System.ComponentModel; using Xunit.Sdk; -namespace MartinCostello.SqlLocalDb +namespace MartinCostello.SqlLocalDb; + +[Serializable] +internal sealed class RetryTestCase : XunitTestCase { - [Serializable] - internal sealed class RetryTestCase : XunitTestCase + private int _maxRetries; + + [EditorBrowsable(EditorBrowsableState.Never)] + [Obsolete("Called by the de-serializer; should only be called by deriving classes for de-serialization purposes")] + public RetryTestCase() + : base() { - private int _maxRetries; + } - [EditorBrowsable(EditorBrowsableState.Never)] - [Obsolete("Called by the de-serializer; should only be called by deriving classes for de-serialization purposes")] - public RetryTestCase() - : base() - { - } + internal RetryTestCase(IMessageSink diagnosticMessageSink, TestMethodDisplay testMethodDisplay, TestMethodDisplayOptions defaultMethodDisplayOptions, ITestMethod testMethod, int maxRetries) + : base(diagnosticMessageSink, testMethodDisplay, defaultMethodDisplayOptions, testMethod, testMethodArguments: null) + { + _maxRetries = maxRetries; + } - internal RetryTestCase(IMessageSink diagnosticMessageSink, TestMethodDisplay testMethodDisplay, TestMethodDisplayOptions defaultMethodDisplayOptions, ITestMethod testMethod, int maxRetries) - : base(diagnosticMessageSink, testMethodDisplay, defaultMethodDisplayOptions, testMethod, testMethodArguments: null) - { - _maxRetries = maxRetries; - } + // This method is called by the xUnit test framework classes to run the test case. We will do the + // loop here, forwarding on to the implementation in XunitTestCase to do the heavy lifting. We will + // continue to re-run the test until the aggregator has an error (meaning that some internal error + // condition happened), or the test runs without failure, or we've hit the maximum number of tries. + public override async Task RunAsync( + IMessageSink diagnosticMessageSink, + IMessageBus messageBus, + object[] constructorArguments, + ExceptionAggregator aggregator, + CancellationTokenSource cancellationTokenSource) + { + int runCount = 0; - // This method is called by the xUnit test framework classes to run the test case. We will do the - // loop here, forwarding on to the implementation in XunitTestCase to do the heavy lifting. We will - // continue to re-run the test until the aggregator has an error (meaning that some internal error - // condition happened), or the test runs without failure, or we've hit the maximum number of tries. - public override async Task RunAsync( - IMessageSink diagnosticMessageSink, - IMessageBus messageBus, - object[] constructorArguments, - ExceptionAggregator aggregator, - CancellationTokenSource cancellationTokenSource) + while (true) { - int runCount = 0; - - while (true) - { - // This is really the only tricky bit: we need to capture and delay messages (since those will - // contain run status) until we know we've decided to accept the final result; - var delayedMessageBus = new DelayedMessageBus(messageBus); + // This is really the only tricky bit: we need to capture and delay messages (since those will + // contain run status) until we know we've decided to accept the final result; + var delayedMessageBus = new DelayedMessageBus(messageBus); - RunSummary summary = await base.RunAsync(diagnosticMessageSink, delayedMessageBus, constructorArguments, aggregator, cancellationTokenSource); + RunSummary summary = await base.RunAsync(diagnosticMessageSink, delayedMessageBus, constructorArguments, aggregator, cancellationTokenSource); - if (aggregator.HasExceptions || summary.Failed == 0 || ++runCount >= _maxRetries) - { - delayedMessageBus.Dispose(); // Sends all the delayed messages - return summary; - } - - diagnosticMessageSink.OnMessage(new DiagnosticMessage("Execution of '{0}' failed (attempt #{1}), retrying...", DisplayName, runCount)); + if (aggregator.HasExceptions || summary.Failed == 0 || ++runCount >= _maxRetries) + { + delayedMessageBus.Dispose(); // Sends all the delayed messages + return summary; } + + diagnosticMessageSink.OnMessage(new DiagnosticMessage("Execution of '{0}' failed (attempt #{1}), retrying...", DisplayName, runCount)); } + } - public override void Serialize(IXunitSerializationInfo data) - { - base.Serialize(data); + public override void Serialize(IXunitSerializationInfo data) + { + base.Serialize(data); - data.AddValue("MaxRetries", _maxRetries); - } + data.AddValue("MaxRetries", _maxRetries); + } - public override void Deserialize(IXunitSerializationInfo data) - { - base.Deserialize(data); + public override void Deserialize(IXunitSerializationInfo data) + { + base.Deserialize(data); - _maxRetries = data.GetValue("MaxRetries"); - } + _maxRetries = data.GetValue("MaxRetries"); } } diff --git a/tests/SqlLocalDb.Tests/RunAsAdminFactAttribute.cs b/tests/SqlLocalDb.Tests/RunAsAdminFactAttribute.cs index 5f6d7930..5a620f0a 100644 --- a/tests/SqlLocalDb.Tests/RunAsAdminFactAttribute.cs +++ b/tests/SqlLocalDb.Tests/RunAsAdminFactAttribute.cs @@ -4,58 +4,57 @@ using System.Security.Principal; using Xunit.Sdk; -namespace MartinCostello.SqlLocalDb +namespace MartinCostello.SqlLocalDb; + +/// +/// Attribute that is applied to a method to indicate that it is a fact that should be run by the test runner +/// if the user account running the test has administrative privileges. This class cannot be inherited. +/// +[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] +[XunitTestCaseDiscoverer("MartinCostello.SqlLocalDb.RetryFactDiscoverer", "MartinCostello.SqlLocalDb.Tests")] +public sealed class RunAsAdminFactAttribute : FactAttribute { + public RunAsAdminFactAttribute() + : base() + { + Skip = IsCurrentUserAdmin(out string name) ? string.Empty : $"The current user '{name}' does not have administrative privileges."; + } + + /// + /// Gets or sets the number of retries allowed for a failed test. + /// If unset (or set less than 1), will default to 3 attempts. + /// + public int MaxRetries { get; set; } + /// - /// Attribute that is applied to a method to indicate that it is a fact that should be run by the test runner - /// if the user account running the test has administrative privileges. This class cannot be inherited. + /// Returns whether the current user has Administrative privileges. /// - [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] - [XunitTestCaseDiscoverer("MartinCostello.SqlLocalDb.RetryFactDiscoverer", "MartinCostello.SqlLocalDb.Tests")] - public sealed class RunAsAdminFactAttribute : FactAttribute + /// + /// if the current user has Administrative + /// privileges; otherwise . + /// + internal static bool IsCurrentUserAdmin() => IsCurrentUserAdmin(out string _); + + /// + /// Returns whether the current user has Administrative privileges. + /// + /// When the method returns, contains the name of the current user. + /// + /// if the current user has Administrative + /// privileges; otherwise . + /// + private static bool IsCurrentUserAdmin(out string name) { - public RunAsAdminFactAttribute() - : base() + if (!OperatingSystem.IsWindows()) { - Skip = IsCurrentUserAdmin(out string name) ? string.Empty : $"The current user '{name}' does not have administrative privileges."; + name = Environment.UserName; + return false; } - /// - /// Gets or sets the number of retries allowed for a failed test. - /// If unset (or set less than 1), will default to 3 attempts. - /// - public int MaxRetries { get; set; } - - /// - /// Returns whether the current user has Administrative privileges. - /// - /// - /// if the current user has Administrative - /// privileges; otherwise . - /// - internal static bool IsCurrentUserAdmin() => IsCurrentUserAdmin(out string _); - - /// - /// Returns whether the current user has Administrative privileges. - /// - /// When the method returns, contains the name of the current user. - /// - /// if the current user has Administrative - /// privileges; otherwise . - /// - private static bool IsCurrentUserAdmin(out string name) + using (var identity = WindowsIdentity.GetCurrent()) { - if (!OperatingSystem.IsWindows()) - { - name = Environment.UserName; - return false; - } - - using (var identity = WindowsIdentity.GetCurrent()) - { - name = identity.Name; - return new WindowsPrincipal(identity).IsInRole(WindowsBuiltInRole.Administrator); - } + name = identity.Name; + return new WindowsPrincipal(identity).IsInRole(WindowsBuiltInRole.Administrator); } } } diff --git a/tests/SqlLocalDb.Tests/SqlLocalDbApiTests.cs b/tests/SqlLocalDb.Tests/SqlLocalDbApiTests.cs index 4cf02f5a..dd46951d 100644 --- a/tests/SqlLocalDb.Tests/SqlLocalDbApiTests.cs +++ b/tests/SqlLocalDb.Tests/SqlLocalDbApiTests.cs @@ -5,391 +5,390 @@ using Microsoft.Extensions.Logging; using Moq; -namespace MartinCostello.SqlLocalDb +namespace MartinCostello.SqlLocalDb; + +public class SqlLocalDbApiTests { - public class SqlLocalDbApiTests + private readonly ILoggerFactory _loggerFactory; + + public SqlLocalDbApiTests(ITestOutputHelper outputHelper) { - private readonly ILoggerFactory _loggerFactory; + _loggerFactory = outputHelper.ToLoggerFactory(); + } - public SqlLocalDbApiTests(ITestOutputHelper outputHelper) - { - _loggerFactory = outputHelper.ToLoggerFactory(); - } + [Fact] + public void Constructor_Validates_Parameters() + { + // Arrange + var options = new SqlLocalDbOptions(); + + Assert.Throws("options", () => new SqlLocalDbApi(null!, _loggerFactory)); + Assert.Throws("loggerFactory", () => new SqlLocalDbApi(null!)); + Assert.Throws("loggerFactory", () => new SqlLocalDbApi(options, null!)); + Assert.Throws("registry", () => new SqlLocalDbApi(options, null!, _loggerFactory)); + } - [Fact] - public void Constructor_Validates_Parameters() + [WindowsOnlyFact] + public void Constructor_Initializes_Instance() + { + // Arrange + var options = new SqlLocalDbOptions() { - // Arrange - var options = new SqlLocalDbOptions(); + AutomaticallyDeleteInstanceFiles = true, + Language = CultureInfo.GetCultureInfo("de-DE"), + NativeApiOverrideVersion = "11.0", + StopOptions = StopInstanceOptions.NoWait, + StopTimeout = TimeSpan.FromSeconds(30), + }; + + // Act + using var actual = new SqlLocalDbApi(options, _loggerFactory); + + // Assert + actual.AutomaticallyDeleteInstanceFiles.ShouldBe(options.AutomaticallyDeleteInstanceFiles); + actual.DefaultInstanceName.ShouldNotBeNull(); + actual.LanguageId.ShouldBeGreaterThan(0); + actual.LatestVersion.ShouldNotBeNull(); + actual.LoggerFactory.ShouldNotBeNull(); + actual.StopOptions.ShouldBe(options.StopOptions); + actual.StopTimeout.ShouldBe(options.StopTimeout); + actual.Versions.ShouldNotBeNull(); + actual.Versions.ShouldNotBeEmpty(); + actual.Versions.ShouldBeUnique(); + } - Assert.Throws("options", () => new SqlLocalDbApi(null!, _loggerFactory)); - Assert.Throws("loggerFactory", () => new SqlLocalDbApi(null!)); - Assert.Throws("loggerFactory", () => new SqlLocalDbApi(options, null!)); - Assert.Throws("registry", () => new SqlLocalDbApi(options, null!, _loggerFactory)); - } + [WindowsOnlyFact] + public void Can_Get_Instances_From_Names() + { + // Arrange + using var api = new SqlLocalDbApi(_loggerFactory); - [WindowsOnlyFact] - public void Constructor_Initializes_Instance() - { - // Arrange - var options = new SqlLocalDbOptions() - { - AutomaticallyDeleteInstanceFiles = true, - Language = CultureInfo.GetCultureInfo("de-DE"), - NativeApiOverrideVersion = "11.0", - StopOptions = StopInstanceOptions.NoWait, - StopTimeout = TimeSpan.FromSeconds(30), - }; + IReadOnlyList names = api.GetInstanceNames(); + foreach (string name in names) + { // Act - using var actual = new SqlLocalDbApi(options, _loggerFactory); + ISqlLocalDbInstanceInfo info = api.GetInstanceInfo(name); // Assert - actual.AutomaticallyDeleteInstanceFiles.ShouldBe(options.AutomaticallyDeleteInstanceFiles); - actual.DefaultInstanceName.ShouldNotBeNull(); - actual.LanguageId.ShouldBeGreaterThan(0); - actual.LatestVersion.ShouldNotBeNull(); - actual.LoggerFactory.ShouldNotBeNull(); - actual.StopOptions.ShouldBe(options.StopOptions); - actual.StopTimeout.ShouldBe(options.StopTimeout); - actual.Versions.ShouldNotBeNull(); - actual.Versions.ShouldNotBeEmpty(); - actual.Versions.ShouldBeUnique(); + info.ShouldNotBeNull(); } - [WindowsOnlyFact] - public void Can_Get_Instances_From_Names() - { - // Arrange - using var api = new SqlLocalDbApi(_loggerFactory); + // Arrange + string instanceName = Guid.NewGuid().ToString(); - IReadOnlyList names = api.GetInstanceNames(); + // Act + bool actual = api.InstanceExists(instanceName); - foreach (string name in names) - { - // Act - ISqlLocalDbInstanceInfo info = api.GetInstanceInfo(name); + // Assert + actual.ShouldBeFalse(); + } + + [WindowsOnlyFact] + public void Can_Test_Whether_Instances_Exist() + { + // Arrange + using var api = new SqlLocalDbApi(_loggerFactory); - // Assert - info.ShouldNotBeNull(); - } + // Start the default instance to ensure it exists + api.StartInstance(api.DefaultInstanceName); + try + { // Arrange - string instanceName = Guid.NewGuid().ToString(); + string instanceName = api.DefaultInstanceName; // Act bool actual = api.InstanceExists(instanceName); + // Assert + actual.ShouldBeTrue(); + + // Arrange + instanceName = Guid.NewGuid().ToString(); + + // Act + actual = api.InstanceExists(instanceName); + // Assert actual.ShouldBeFalse(); } - - [WindowsOnlyFact] - public void Can_Test_Whether_Instances_Exist() + finally { - // Arrange - using var api = new SqlLocalDbApi(_loggerFactory); + api.StopInstance(api.DefaultInstanceName); + } + } - // Start the default instance to ensure it exists - api.StartInstance(api.DefaultInstanceName); + [NotWindowsFact] + public void Does_Not_Throw_PlatformNotSupportedException() + { + // Arrange + using var actual = new SqlLocalDbApi(_loggerFactory); - try - { - // Arrange - string instanceName = api.DefaultInstanceName; + // Act and Assert + actual.DefaultInstanceName.ShouldBe(string.Empty); + actual.IsLocalDBInstalled().ShouldBeFalse(); + actual.Versions.ShouldBeEmpty(); + } - // Act - bool actual = api.InstanceExists(instanceName); + [NotWindowsFact] + public void Throws_PlatformNotSupportedException() + { + // Arrange + using var actual = new SqlLocalDbApi(_loggerFactory); + + // Act and Assert + Assert.Throws(() => actual.CreateInstance("name")); + Assert.Throws(() => actual.DeleteInstance("name")); + Assert.Throws(() => actual.DeleteUserInstances()); + Assert.Throws(() => actual.GetDefaultInstance()); + Assert.Throws(() => actual.GetInstanceInfo("name")); + Assert.Throws(() => actual.GetInstanceNames()); + Assert.Throws(() => actual.GetInstances()); + Assert.Throws(() => actual.GetOrCreateInstance("name")); + Assert.Throws(() => actual.GetVersionInfo("name")); + Assert.Throws(() => actual.InstanceExists("name")); + Assert.Throws(() => actual.LatestVersion); + Assert.Throws(() => actual.ShareInstance("name", "sharedName")); + Assert.Throws(() => actual.ShareInstance("sid", "name", "sharedName")); + Assert.Throws(() => actual.StartInstance("name")); + Assert.Throws(() => actual.StartTracing()); + Assert.Throws(() => actual.StopInstance("name")); + Assert.Throws(() => actual.StopTracing()); + Assert.Throws(() => actual.UnshareInstance("name")); + } - // Assert - actual.ShouldBeTrue(); + [WindowsOnlyFact] + public void Can_Start_And_Stop_Tracing() + { + // Arrange + using var api = new SqlLocalDbApi(_loggerFactory); - // Arrange - instanceName = Guid.NewGuid().ToString(); + // Act (no Assert) + api.StartTracing(); + api.StopTracing(); + } - // Act - actual = api.InstanceExists(instanceName); + [WindowsOnlyFact] + public void Throws_InvalidOperationException_If_SQL_LocalDB_Not_Installed() + { + // Arrange + var options = new SqlLocalDbOptions(); + var registry = Mock.Of(); + + using var actual = new SqlLocalDbApi(options, registry, _loggerFactory); + + // Act and Assert + Assert.Throws(() => actual.CreateInstance("name")); + Assert.Throws(() => actual.DeleteInstance("name")); + Assert.Throws(() => actual.DeleteUserInstances()); + Assert.Throws(() => actual.GetDefaultInstance()); + Assert.Throws(() => actual.GetInstanceInfo("name")); + Assert.Throws(() => actual.GetInstanceNames()); + Assert.Throws(() => actual.GetInstances()); + Assert.Throws(() => actual.GetOrCreateInstance("name")); + Assert.Throws(() => actual.GetVersionInfo("name")); + Assert.Throws(() => actual.InstanceExists("name")); + Assert.Throws(() => actual.LatestVersion); + Assert.Throws(() => actual.ShareInstance("name", "sharedName")); + Assert.Throws(() => actual.StartInstance("name")); + Assert.Throws(() => actual.StartTracing()); + Assert.Throws(() => actual.StopInstance("name")); + Assert.Throws(() => actual.StopTracing()); + Assert.Throws(() => actual.UnshareInstance("name")); + } - // Assert - actual.ShouldBeFalse(); - } - finally - { - api.StopInstance(api.DefaultInstanceName); - } - } + [WindowsOnlyFact] + public void StopTimeout_Throws_If_Value_Is_Negative() + { + // Arrange + TimeSpan value = TimeSpan.Zero.Add(TimeSpan.FromTicks(-1)); - [NotWindowsFact] - public void Does_Not_Throw_PlatformNotSupportedException() - { - // Arrange - using var actual = new SqlLocalDbApi(_loggerFactory); + using var actual = new SqlLocalDbApi(_loggerFactory); - // Act and Assert - actual.DefaultInstanceName.ShouldBe(string.Empty); - actual.IsLocalDBInstalled().ShouldBeFalse(); - actual.Versions.ShouldBeEmpty(); - } + // Act and Assert + var exception = Assert.Throws("value", () => actual.StopTimeout = value); + exception.ActualValue.ShouldBe(value); + } - [NotWindowsFact] - public void Throws_PlatformNotSupportedException() - { - // Arrange - using var actual = new SqlLocalDbApi(_loggerFactory); - - // Act and Assert - Assert.Throws(() => actual.CreateInstance("name")); - Assert.Throws(() => actual.DeleteInstance("name")); - Assert.Throws(() => actual.DeleteUserInstances()); - Assert.Throws(() => actual.GetDefaultInstance()); - Assert.Throws(() => actual.GetInstanceInfo("name")); - Assert.Throws(() => actual.GetInstanceNames()); - Assert.Throws(() => actual.GetInstances()); - Assert.Throws(() => actual.GetOrCreateInstance("name")); - Assert.Throws(() => actual.GetVersionInfo("name")); - Assert.Throws(() => actual.InstanceExists("name")); - Assert.Throws(() => actual.LatestVersion); - Assert.Throws(() => actual.ShareInstance("name", "sharedName")); - Assert.Throws(() => actual.ShareInstance("sid", "name", "sharedName")); - Assert.Throws(() => actual.StartInstance("name")); - Assert.Throws(() => actual.StartTracing()); - Assert.Throws(() => actual.StopInstance("name")); - Assert.Throws(() => actual.StopTracing()); - Assert.Throws(() => actual.UnshareInstance("name")); - } + [WindowsOnlyFact] + public void Methods_Validate_Parameters() + { + // Arrange + TimeSpan timeout = TimeSpan.Zero.Add(TimeSpan.FromTicks(-1)); + + using var actual = new SqlLocalDbApi(_loggerFactory); + + // Act and Assert + Assert.Throws("instanceName", () => actual.CreateInstance(null!, "version")); + Assert.Throws("version", () => actual.CreateInstance("instanceName", null!)); + Assert.Throws("instanceName", () => actual.DeleteInstance(null!)); + Assert.Throws("instanceName", () => actual.GetInstanceInfo(null!)); + Assert.Throws("version", () => actual.GetVersionInfo(null!)); + Assert.Throws("ownerSid", () => actual.ShareInstance(null!, "instanceName", "sharedInstanceName")); + Assert.Throws("instanceName", () => actual.ShareInstance("ownerSid", null!, "sharedInstanceName")); + Assert.Throws("sharedInstanceName", () => actual.ShareInstance("ownerSid", "instanceName", null!)); + Assert.Throws("instanceName", () => actual.ShareInstance("sid", string.Empty, "sharedInstanceName")); + Assert.Throws("instanceName", () => actual.StartInstance(null!)); + Assert.Throws("instanceName", () => actual.StopInstance(null!, TimeSpan.Zero)); + Assert.Throws("timeout", () => actual.StopInstance("instanceName", timeout)).ActualValue.ShouldBe(timeout); + Assert.Throws("instanceName", () => actual.UnshareInstance(null!)); + } - [WindowsOnlyFact] - public void Can_Start_And_Stop_Tracing() - { - // Arrange - using var api = new SqlLocalDbApi(_loggerFactory); + [WindowsOnlyFact] + public void DeleteInstanceInternal_Returns_False_If_ThrownIfNotFound_Is_False_And_Instance_Does_Not_Exist() + { + // Arrange + using var actual = new SqlLocalDbApi(_loggerFactory); - // Act (no Assert) - api.StartTracing(); - api.StopTracing(); - } + // Act and Assert + actual.DeleteInstanceInternal("NotARealInstance", throwIfNotFound: false).ShouldBeFalse(); + } - [WindowsOnlyFact] - public void Throws_InvalidOperationException_If_SQL_LocalDB_Not_Installed() - { - // Arrange - var options = new SqlLocalDbOptions(); - var registry = Mock.Of(); - - using var actual = new SqlLocalDbApi(options, registry, _loggerFactory); - - // Act and Assert - Assert.Throws(() => actual.CreateInstance("name")); - Assert.Throws(() => actual.DeleteInstance("name")); - Assert.Throws(() => actual.DeleteUserInstances()); - Assert.Throws(() => actual.GetDefaultInstance()); - Assert.Throws(() => actual.GetInstanceInfo("name")); - Assert.Throws(() => actual.GetInstanceNames()); - Assert.Throws(() => actual.GetInstances()); - Assert.Throws(() => actual.GetOrCreateInstance("name")); - Assert.Throws(() => actual.GetVersionInfo("name")); - Assert.Throws(() => actual.InstanceExists("name")); - Assert.Throws(() => actual.LatestVersion); - Assert.Throws(() => actual.ShareInstance("name", "sharedName")); - Assert.Throws(() => actual.StartInstance("name")); - Assert.Throws(() => actual.StartTracing()); - Assert.Throws(() => actual.StopInstance("name")); - Assert.Throws(() => actual.StopTracing()); - Assert.Throws(() => actual.UnshareInstance("name")); - } + [WindowsOnlyFact] + public async Task Can_Manage_SqlLocalDB_Instances() + { + // Arrange + using var actual = new SqlLocalDbApi(_loggerFactory); + string instanceName = Guid.NewGuid().ToString(); - [WindowsOnlyFact] - public void StopTimeout_Throws_If_Value_Is_Negative() - { - // Arrange - TimeSpan value = TimeSpan.Zero.Add(TimeSpan.FromTicks(-1)); + // Act + ISqlLocalDbInstanceInfo instance = actual.GetInstanceInfo(instanceName); - using var actual = new SqlLocalDbApi(_loggerFactory); + // Assert + instance.ShouldNotBeNull(); + instance.Name.ShouldBe(instanceName); + instance.Exists.ShouldBeFalse(); + instance.IsRunning.ShouldBeFalse(); - // Act and Assert - var exception = Assert.Throws("value", () => actual.StopTimeout = value); - exception.ActualValue.ShouldBe(value); - } + // Act and Assert + actual.InstanceExists(instanceName).ShouldBeFalse(); - [WindowsOnlyFact] - public void Methods_Validate_Parameters() - { - // Arrange - TimeSpan timeout = TimeSpan.Zero.Add(TimeSpan.FromTicks(-1)); - - using var actual = new SqlLocalDbApi(_loggerFactory); - - // Act and Assert - Assert.Throws("instanceName", () => actual.CreateInstance(null!, "version")); - Assert.Throws("version", () => actual.CreateInstance("instanceName", null!)); - Assert.Throws("instanceName", () => actual.DeleteInstance(null!)); - Assert.Throws("instanceName", () => actual.GetInstanceInfo(null!)); - Assert.Throws("version", () => actual.GetVersionInfo(null!)); - Assert.Throws("ownerSid", () => actual.ShareInstance(null!, "instanceName", "sharedInstanceName")); - Assert.Throws("instanceName", () => actual.ShareInstance("ownerSid", null!, "sharedInstanceName")); - Assert.Throws("sharedInstanceName", () => actual.ShareInstance("ownerSid", "instanceName", null!)); - Assert.Throws("instanceName", () => actual.ShareInstance("sid", string.Empty, "sharedInstanceName")); - Assert.Throws("instanceName", () => actual.StartInstance(null!)); - Assert.Throws("instanceName", () => actual.StopInstance(null!, TimeSpan.Zero)); - Assert.Throws("timeout", () => actual.StopInstance("instanceName", timeout)).ActualValue.ShouldBe(timeout); - Assert.Throws("instanceName", () => actual.UnshareInstance(null!)); - } + // Act + instance = actual.CreateInstance(instanceName); - [WindowsOnlyFact] - public void DeleteInstanceInternal_Returns_False_If_ThrownIfNotFound_Is_False_And_Instance_Does_Not_Exist() - { - // Arrange - using var actual = new SqlLocalDbApi(_loggerFactory); + // Assert + instance = actual.GetInstanceInfo(instanceName); + instance.ShouldNotBeNull(); + instance.Name.ShouldBe(instanceName); + instance.Exists.ShouldBeTrue(); + instance.IsRunning.ShouldBeFalse(); - // Act and Assert - actual.DeleteInstanceInternal("NotARealInstance", throwIfNotFound: false).ShouldBeFalse(); - } + // Act + string namedPipe = actual.StartInstance(instanceName); - [WindowsOnlyFact] - public async Task Can_Manage_SqlLocalDB_Instances() - { - // Arrange - using var actual = new SqlLocalDbApi(_loggerFactory); - string instanceName = Guid.NewGuid().ToString(); + // Assert + namedPipe.ShouldNotBeNullOrWhiteSpace(); - // Act - ISqlLocalDbInstanceInfo instance = actual.GetInstanceInfo(instanceName); + var builder = new SqlConnectionStringBuilder() { DataSource = namedPipe }; - // Assert - instance.ShouldNotBeNull(); - instance.Name.ShouldBe(instanceName); - instance.Exists.ShouldBeFalse(); - instance.IsRunning.ShouldBeFalse(); + await using (var connection = new SqlConnection(builder.ConnectionString)) + { + await connection.OpenAsync(); + } - // Act and Assert - actual.InstanceExists(instanceName).ShouldBeFalse(); + // Act + instance = actual.GetInstanceInfo(instanceName); - // Act - instance = actual.CreateInstance(instanceName); + // Assert + instance.ShouldNotBeNull(); + instance.Name.ShouldBe(instanceName); + instance.Exists.ShouldBeTrue(); + instance.IsRunning.ShouldBeTrue(); - // Assert - instance = actual.GetInstanceInfo(instanceName); - instance.ShouldNotBeNull(); - instance.Name.ShouldBe(instanceName); - instance.Exists.ShouldBeTrue(); - instance.IsRunning.ShouldBeFalse(); + // Act and Assert + actual.InstanceExists(instanceName).ShouldBeTrue(); - // Act - string namedPipe = actual.StartInstance(instanceName); + // Act + actual.StopInstance(instanceName); - // Assert - namedPipe.ShouldNotBeNullOrWhiteSpace(); + // Assert + instance = actual.GetInstanceInfo(instanceName); + instance.ShouldNotBeNull(); + instance.Name.ShouldBe(instanceName); + instance.Exists.ShouldBeTrue(); + instance.IsRunning.ShouldBeFalse(); - var builder = new SqlConnectionStringBuilder() { DataSource = namedPipe }; + // Act + actual.DeleteInstance(instanceName); - await using (var connection = new SqlConnection(builder.ConnectionString)) - { - await connection.OpenAsync(); - } + // Assert + instance = actual.GetInstanceInfo(instanceName); + instance.ShouldNotBeNull(); + instance.Name.ShouldBe(instanceName); + instance.Exists.ShouldBeFalse(); + instance.IsRunning.ShouldBeFalse(); - // Act - instance = actual.GetInstanceInfo(instanceName); + // Act and Assert + actual.InstanceExists(instanceName).ShouldBeFalse(); - // Assert - instance.ShouldNotBeNull(); - instance.Name.ShouldBe(instanceName); - instance.Exists.ShouldBeTrue(); - instance.IsRunning.ShouldBeTrue(); + // Act (no Assert) + actual.DeleteInstanceFiles(instanceName); + } - // Act and Assert - actual.InstanceExists(instanceName).ShouldBeTrue(); + [WindowsOnlyFact] + public void Can_Create_SqlLocalDB_Instances_With_Different_Versions() + { + // Arrange + using var actual = new SqlLocalDbApi(_loggerFactory); + foreach (string version in actual.Versions) + { // Act - actual.StopInstance(instanceName); + ISqlLocalDbVersionInfo versionInfo = actual.GetVersionInfo(version); // Assert - instance = actual.GetInstanceInfo(instanceName); - instance.ShouldNotBeNull(); - instance.Name.ShouldBe(instanceName); - instance.Exists.ShouldBeTrue(); - instance.IsRunning.ShouldBeFalse(); + versionInfo.ShouldNotBeNull(); + versionInfo.Name.ShouldStartWith(version.Split('.').First()); + versionInfo.Exists.ShouldBeTrue(); + versionInfo.Version.ShouldNotBeNull(); + versionInfo.Version.ShouldNotBe(new Version()); + + string instanceName = Guid.NewGuid().ToString(); // Act - actual.DeleteInstance(instanceName); + ISqlLocalDbInstanceInfo instanceInfo = actual.CreateInstance(instanceName, version); // Assert - instance = actual.GetInstanceInfo(instanceName); - instance.ShouldNotBeNull(); - instance.Name.ShouldBe(instanceName); - instance.Exists.ShouldBeFalse(); - instance.IsRunning.ShouldBeFalse(); - - // Act and Assert - actual.InstanceExists(instanceName).ShouldBeFalse(); + instanceInfo.ShouldNotBeNull(); + instanceInfo.Name.ShouldBe(instanceName); + instanceInfo.Exists.ShouldBeTrue(); + instanceInfo.IsRunning.ShouldBeFalse(); + instanceInfo.LocalDbVersion.ShouldBe(versionInfo.Version); // Act (no Assert) + actual.DeleteInstance(instanceName); actual.DeleteInstanceFiles(instanceName); } + } - [WindowsOnlyFact] - public void Can_Create_SqlLocalDB_Instances_With_Different_Versions() - { - // Arrange - using var actual = new SqlLocalDbApi(_loggerFactory); - - foreach (string version in actual.Versions) - { - // Act - ISqlLocalDbVersionInfo versionInfo = actual.GetVersionInfo(version); - - // Assert - versionInfo.ShouldNotBeNull(); - versionInfo.Name.ShouldStartWith(version.Split('.').First()); - versionInfo.Exists.ShouldBeTrue(); - versionInfo.Version.ShouldNotBeNull(); - versionInfo.Version.ShouldNotBe(new Version()); - - string instanceName = Guid.NewGuid().ToString(); - - // Act - ISqlLocalDbInstanceInfo instanceInfo = actual.CreateInstance(instanceName, version); - - // Assert - instanceInfo.ShouldNotBeNull(); - instanceInfo.Name.ShouldBe(instanceName); - instanceInfo.Exists.ShouldBeTrue(); - instanceInfo.IsRunning.ShouldBeFalse(); - instanceInfo.LocalDbVersion.ShouldBe(versionInfo.Version); - - // Act (no Assert) - actual.DeleteInstance(instanceName); - actual.DeleteInstanceFiles(instanceName); - } - } - - [Fact] - public void SqlLocalDbApi_Is_ISqlLocalDbApiAdapter() - { - // Arrange - using var instance = new SqlLocalDbApi(_loggerFactory); + [Fact] + public void SqlLocalDbApi_Is_ISqlLocalDbApiAdapter() + { + // Arrange + using var instance = new SqlLocalDbApi(_loggerFactory); - // Act - ISqlLocalDbApiAdapter adapter = instance; + // Act + ISqlLocalDbApiAdapter adapter = instance; - // Assert - adapter.LocalDb.ShouldBeSameAs(instance); - } + // Assert + adapter.LocalDb.ShouldBeSameAs(instance); + } - [WindowsOnlyFact] - public void SqlLocalDbApi_Throws_Exception_For_Native_Errors() - { - // Arrange - string instanceName = new string('$', 10000); + [WindowsOnlyFact] + public void SqlLocalDbApi_Throws_Exception_For_Native_Errors() + { + // Arrange + string instanceName = new string('$', 10000); - using var actual = new SqlLocalDbApi(_loggerFactory); + using var actual = new SqlLocalDbApi(_loggerFactory); - // Act - var exception = Assert.Throws(() => actual.CreateInstance(instanceName)); + // Act + var exception = Assert.Throws(() => actual.CreateInstance(instanceName)); - // Assert - exception.ErrorCode.ShouldBe(SqlLocalDbErrors.InvalidParameter); - exception.Message.ShouldStartWith("The parameter for the LocalDB Instance API method is incorrect. Consult the API documentation."); - exception.InstanceName.ShouldBe(instanceName); - } + // Assert + exception.ErrorCode.ShouldBe(SqlLocalDbErrors.InvalidParameter); + exception.Message.ShouldStartWith("The parameter for the LocalDB Instance API method is incorrect. Consult the API documentation."); + exception.InstanceName.ShouldBe(instanceName); } } diff --git a/tests/SqlLocalDb.Tests/SqlLocalDbExceptionTests.cs b/tests/SqlLocalDb.Tests/SqlLocalDbExceptionTests.cs index f2384cd0..12a4cb0a 100644 --- a/tests/SqlLocalDb.Tests/SqlLocalDbExceptionTests.cs +++ b/tests/SqlLocalDb.Tests/SqlLocalDbExceptionTests.cs @@ -3,117 +3,116 @@ using System.Runtime.Serialization; -namespace MartinCostello.SqlLocalDb +namespace MartinCostello.SqlLocalDb; + +public static class SqlLocalDbExceptionTests { - public static class SqlLocalDbExceptionTests + [Fact] + public static void SqlLocalDbException_Constructor_Default_Sets_Properties() + { + // Act + var target = new SqlLocalDbException(); + + // Assert + target.ErrorCode.ShouldBe(-2147467259); + target.InstanceName.ShouldBeNull(); + target.Message.ShouldBe("An error occurred with a SQL Server LocalDB instance."); + } + + [Fact] + public static void SqlLocalDbException_Constructor_With_Message_Sets_Properties() + { + // Arrange + string message = Guid.NewGuid().ToString(); + + // Act + var target = new SqlLocalDbException(message); + + // Assert + target.ErrorCode.ShouldBe(-2147467259); + target.InstanceName.ShouldBeNull(); + target.Message.ShouldBe(message); + } + + [Fact] + public static void SqlLocalDbException_Constructor_With_Message_And_InnerException_Sets_Properties() + { + // Arrange + var innerException = new InvalidOperationException(); + string message = Guid.NewGuid().ToString(); + + // Act + var target = new SqlLocalDbException(message, innerException); + + // Assert + target.ErrorCode.ShouldBe(-2147467259); + target.InnerException.ShouldBeSameAs(innerException); + target.InstanceName.ShouldBeNull(); + target.Message.ShouldBe(message); + } + + [Fact] + public static void SqlLocalDbException_Constructor_With_Message_And_ErrorCode_Sets_Properties() { - [Fact] - public static void SqlLocalDbException_Constructor_Default_Sets_Properties() - { - // Act - var target = new SqlLocalDbException(); - - // Assert - target.ErrorCode.ShouldBe(-2147467259); - target.InstanceName.ShouldBeNull(); - target.Message.ShouldBe("An error occurred with a SQL Server LocalDB instance."); - } - - [Fact] - public static void SqlLocalDbException_Constructor_With_Message_Sets_Properties() - { - // Arrange - string message = Guid.NewGuid().ToString(); - - // Act - var target = new SqlLocalDbException(message); - - // Assert - target.ErrorCode.ShouldBe(-2147467259); - target.InstanceName.ShouldBeNull(); - target.Message.ShouldBe(message); - } - - [Fact] - public static void SqlLocalDbException_Constructor_With_Message_And_InnerException_Sets_Properties() - { - // Arrange - var innerException = new InvalidOperationException(); - string message = Guid.NewGuid().ToString(); - - // Act - var target = new SqlLocalDbException(message, innerException); - - // Assert - target.ErrorCode.ShouldBe(-2147467259); - target.InnerException.ShouldBeSameAs(innerException); - target.InstanceName.ShouldBeNull(); - target.Message.ShouldBe(message); - } - - [Fact] - public static void SqlLocalDbException_Constructor_With_Message_And_ErrorCode_Sets_Properties() - { - // Arrange - const int ErrorCode = 337519; - string message = Guid.NewGuid().ToString(); - - // Act - var target = new SqlLocalDbException(message, ErrorCode); - - // Assert - target.ErrorCode.ShouldBe(ErrorCode); - target.InstanceName.ShouldBeNull(); - target.Message.ShouldBe(message); - } - - [Fact] - public static void SqlLocalDbException_Constructor_With_Message_ErrorCode_And_InstanceName_Sets_Properties() - { - // Arrange - const int ErrorCode = 337519; - string instanceName = Guid.NewGuid().ToString(); - string message = Guid.NewGuid().ToString(); - - // Act - var target = new SqlLocalDbException(message, ErrorCode, instanceName); - - // Assert - target.ErrorCode.ShouldBe(ErrorCode); - target.InstanceName.ShouldBe(instanceName); - target.Message.ShouldBe(message); - } - - [Fact] - public static void SqlLocalDbException_Constructor_With_Message_ErrorCode_InstanceName_And_InnerException_Sets_Properties() - { - // Arrange - var innerException = new InvalidOperationException(); - const int ErrorCode = 337519; - string instanceName = Guid.NewGuid().ToString(); - string message = Guid.NewGuid().ToString(); - - // Act - var target = new SqlLocalDbException(message, ErrorCode, instanceName, innerException); - - // Assert - target.ErrorCode.ShouldBe(ErrorCode); - target.InnerException.ShouldBeSameAs(innerException); - target.InstanceName.ShouldBe(instanceName); - target.Message.ShouldBe(message); - } - - [Fact] - public static void SqlLocalDbException_GetObjectData_Throws_If_Info_Is_Null() - { - // Arrange - var target = new SqlLocalDbException(); - - SerializationInfo? info = null; - var context = new StreamingContext(); - - // Act and Assert - Assert.Throws("info", () => target.GetObjectData(info!, context)); - } + // Arrange + const int ErrorCode = 337519; + string message = Guid.NewGuid().ToString(); + + // Act + var target = new SqlLocalDbException(message, ErrorCode); + + // Assert + target.ErrorCode.ShouldBe(ErrorCode); + target.InstanceName.ShouldBeNull(); + target.Message.ShouldBe(message); + } + + [Fact] + public static void SqlLocalDbException_Constructor_With_Message_ErrorCode_And_InstanceName_Sets_Properties() + { + // Arrange + const int ErrorCode = 337519; + string instanceName = Guid.NewGuid().ToString(); + string message = Guid.NewGuid().ToString(); + + // Act + var target = new SqlLocalDbException(message, ErrorCode, instanceName); + + // Assert + target.ErrorCode.ShouldBe(ErrorCode); + target.InstanceName.ShouldBe(instanceName); + target.Message.ShouldBe(message); + } + + [Fact] + public static void SqlLocalDbException_Constructor_With_Message_ErrorCode_InstanceName_And_InnerException_Sets_Properties() + { + // Arrange + var innerException = new InvalidOperationException(); + const int ErrorCode = 337519; + string instanceName = Guid.NewGuid().ToString(); + string message = Guid.NewGuid().ToString(); + + // Act + var target = new SqlLocalDbException(message, ErrorCode, instanceName, innerException); + + // Assert + target.ErrorCode.ShouldBe(ErrorCode); + target.InnerException.ShouldBeSameAs(innerException); + target.InstanceName.ShouldBe(instanceName); + target.Message.ShouldBe(message); + } + + [Fact] + public static void SqlLocalDbException_GetObjectData_Throws_If_Info_Is_Null() + { + // Arrange + var target = new SqlLocalDbException(); + + SerializationInfo? info = null; + var context = new StreamingContext(); + + // Act and Assert + Assert.Throws("info", () => target.GetObjectData(info!, context)); } } diff --git a/tests/SqlLocalDb.Tests/SqlLocalDbInstanceInfoTests.cs b/tests/SqlLocalDb.Tests/SqlLocalDbInstanceInfoTests.cs index 240e583f..fcfd2597 100644 --- a/tests/SqlLocalDb.Tests/SqlLocalDbInstanceInfoTests.cs +++ b/tests/SqlLocalDb.Tests/SqlLocalDbInstanceInfoTests.cs @@ -3,139 +3,138 @@ using Moq; -namespace MartinCostello.SqlLocalDb +namespace MartinCostello.SqlLocalDb; + +public static class SqlLocalDbInstanceInfoTests { - public static class SqlLocalDbInstanceInfoTests + [Fact] + public static void Update_Copies_State_From_Other_Instance() { - [Fact] - public static void Update_Copies_State_From_Other_Instance() + // Arrange + var api = Mock.Of(); + + var other = new SqlLocalDbInstanceInfo(api) { - // Arrange - var api = Mock.Of(); - - var other = new SqlLocalDbInstanceInfo(api) - { - ConfigurationCorrupt = true, - Exists = true, - IsAutomatic = true, - IsRunning = true, - IsShared = true, - LastStartTimeUtc = DateTime.UtcNow, - LocalDbVersion = new Version(2, 1), - Name = "OtherName", - NamedPipe = "OtherPipe", - OwnerSid = "Sidney Poitier", - SharedName = "OtherSharedName", - }; - - var actual = new SqlLocalDbInstanceInfo(api) - { - ConfigurationCorrupt = false, - Exists = false, - IsAutomatic = false, - IsRunning = false, - IsShared = false, - LastStartTimeUtc = DateTime.MinValue, - LocalDbVersion = new Version(2, 0), - Name = "Name", - NamedPipe = "OtherPipe", - OwnerSid = "Sid James", - SharedName = "SharedName", - }; - - // Act - actual.Update(other); - - // Assert - actual.ConfigurationCorrupt.ShouldBe(other.ConfigurationCorrupt); - actual.Exists.ShouldBe(other.Exists); - actual.IsAutomatic.ShouldBe(other.IsAutomatic); - actual.IsRunning.ShouldBe(other.IsRunning); - actual.IsShared.ShouldBe(other.IsShared); - actual.LastStartTimeUtc.ShouldBe(other.LastStartTimeUtc); - actual.LocalDbVersion.ShouldBe(other.LocalDbVersion); - actual.Name.ShouldBe(other.Name); - actual.NamedPipe.ShouldBe(other.NamedPipe); - actual.OwnerSid.ShouldBe(other.OwnerSid); - actual.SharedName.ShouldBe(other.SharedName); - } - - [Fact] - public static void Update_Does_Not_Copy_State_If_Other_Is_Null() + ConfigurationCorrupt = true, + Exists = true, + IsAutomatic = true, + IsRunning = true, + IsShared = true, + LastStartTimeUtc = DateTime.UtcNow, + LocalDbVersion = new Version(2, 1), + Name = "OtherName", + NamedPipe = "OtherPipe", + OwnerSid = "Sidney Poitier", + SharedName = "OtherSharedName", + }; + + var actual = new SqlLocalDbInstanceInfo(api) { - // Arrange - var api = Mock.Of(); - - var actual = new SqlLocalDbInstanceInfo(api) - { - ConfigurationCorrupt = true, - Exists = true, - IsAutomatic = true, - IsRunning = true, - IsShared = true, - LastStartTimeUtc = DateTime.UtcNow, - LocalDbVersion = new Version(2, 1), - Name = "Name", - NamedPipe = "NamedPipe", - OwnerSid = "OwnerSid", - SharedName = "SharedName", - }; - - // Act (no Assert) - actual.Update(null!); - } - - [Fact] - public static void Update_Does_Not_Copy_State_If_Other_Is_Self() + ConfigurationCorrupt = false, + Exists = false, + IsAutomatic = false, + IsRunning = false, + IsShared = false, + LastStartTimeUtc = DateTime.MinValue, + LocalDbVersion = new Version(2, 0), + Name = "Name", + NamedPipe = "OtherPipe", + OwnerSid = "Sid James", + SharedName = "SharedName", + }; + + // Act + actual.Update(other); + + // Assert + actual.ConfigurationCorrupt.ShouldBe(other.ConfigurationCorrupt); + actual.Exists.ShouldBe(other.Exists); + actual.IsAutomatic.ShouldBe(other.IsAutomatic); + actual.IsRunning.ShouldBe(other.IsRunning); + actual.IsShared.ShouldBe(other.IsShared); + actual.LastStartTimeUtc.ShouldBe(other.LastStartTimeUtc); + actual.LocalDbVersion.ShouldBe(other.LocalDbVersion); + actual.Name.ShouldBe(other.Name); + actual.NamedPipe.ShouldBe(other.NamedPipe); + actual.OwnerSid.ShouldBe(other.OwnerSid); + actual.SharedName.ShouldBe(other.SharedName); + } + + [Fact] + public static void Update_Does_Not_Copy_State_If_Other_Is_Null() + { + // Arrange + var api = Mock.Of(); + + var actual = new SqlLocalDbInstanceInfo(api) { - // Arrange - var api = Mock.Of(); - - var actual = new SqlLocalDbInstanceInfo(api) - { - ConfigurationCorrupt = true, - Exists = true, - IsAutomatic = true, - IsRunning = true, - IsShared = true, - LastStartTimeUtc = DateTime.UtcNow, - LocalDbVersion = new Version(2, 1), - Name = "Name", - NamedPipe = "NamedPipe", - OwnerSid = "OwnerSid", - SharedName = "SharedName", - }; - - // Act (no Assert) - actual.Update(actual); - } - - [Fact] - public static void ToString_Returns_The_Name() + ConfigurationCorrupt = true, + Exists = true, + IsAutomatic = true, + IsRunning = true, + IsShared = true, + LastStartTimeUtc = DateTime.UtcNow, + LocalDbVersion = new Version(2, 1), + Name = "Name", + NamedPipe = "NamedPipe", + OwnerSid = "OwnerSid", + SharedName = "SharedName", + }; + + // Act (no Assert) + actual.Update(null!); + } + + [Fact] + public static void Update_Does_Not_Copy_State_If_Other_Is_Self() + { + // Arrange + var api = Mock.Of(); + + var actual = new SqlLocalDbInstanceInfo(api) + { + ConfigurationCorrupt = true, + Exists = true, + IsAutomatic = true, + IsRunning = true, + IsShared = true, + LastStartTimeUtc = DateTime.UtcNow, + LocalDbVersion = new Version(2, 1), + Name = "Name", + NamedPipe = "NamedPipe", + OwnerSid = "OwnerSid", + SharedName = "SharedName", + }; + + // Act (no Assert) + actual.Update(actual); + } + + [Fact] + public static void ToString_Returns_The_Name() + { + // Arrange + var api = Mock.Of(); + + var info = new SqlLocalDbInstanceInfo(api) { - // Arrange - var api = Mock.Of(); - - var info = new SqlLocalDbInstanceInfo(api) - { - ConfigurationCorrupt = true, - Exists = true, - IsAutomatic = true, - IsRunning = true, - IsShared = true, - LastStartTimeUtc = DateTime.UtcNow, - LocalDbVersion = new Version(2, 1), - Name = "Name", - NamedPipe = "NamedPipe", - OwnerSid = "OwnerSid", - SharedName = "SharedName", - }; - - // Act and Assert - string actual = info.ToString(); - - // Assert - actual.ShouldBe("Name"); - } + ConfigurationCorrupt = true, + Exists = true, + IsAutomatic = true, + IsRunning = true, + IsShared = true, + LastStartTimeUtc = DateTime.UtcNow, + LocalDbVersion = new Version(2, 1), + Name = "Name", + NamedPipe = "NamedPipe", + OwnerSid = "OwnerSid", + SharedName = "SharedName", + }; + + // Act and Assert + string actual = info.ToString(); + + // Assert + actual.ShouldBe("Name"); } } diff --git a/tests/SqlLocalDb.Tests/SqlLocalDbInstanceManagerTests.cs b/tests/SqlLocalDb.Tests/SqlLocalDbInstanceManagerTests.cs index 1161884c..02dfe1be 100644 --- a/tests/SqlLocalDb.Tests/SqlLocalDbInstanceManagerTests.cs +++ b/tests/SqlLocalDb.Tests/SqlLocalDbInstanceManagerTests.cs @@ -4,286 +4,285 @@ using Microsoft.Extensions.Logging; using Moq; -namespace MartinCostello.SqlLocalDb +namespace MartinCostello.SqlLocalDb; + +public class SqlLocalDbInstanceManagerTests { - public class SqlLocalDbInstanceManagerTests + private readonly ILoggerFactory _loggerFactory; + + public SqlLocalDbInstanceManagerTests(ITestOutputHelper outputHelper) { - private readonly ILoggerFactory _loggerFactory; + _loggerFactory = outputHelper.ToLoggerFactory(); + } - public SqlLocalDbInstanceManagerTests(ITestOutputHelper outputHelper) - { - _loggerFactory = outputHelper.ToLoggerFactory(); - } + [WindowsOnlyFact] + public static void Share_Shares_Instance() + { + // Act + string sharedName = Guid.NewGuid().ToString(); - [WindowsOnlyFact] - public static void Share_Shares_Instance() - { - // Act - string sharedName = Guid.NewGuid().ToString(); + var mock = new Mock(); + ISqlLocalDbInstanceInfo instance = CreateInstance(); + ISqlLocalDbApi api = mock.Object; - var mock = new Mock(); - ISqlLocalDbInstanceInfo instance = CreateInstance(); - ISqlLocalDbApi api = mock.Object; + var target = new SqlLocalDbInstanceManager(instance, api); - var target = new SqlLocalDbInstanceManager(instance, api); + // Act + target.Share(sharedName); - // Act - target.Share(sharedName); + // Assert + mock.Verify((p) => p.ShareInstance(It.IsNotNull(), "Name", sharedName), Times.Once()); + } - // Assert - mock.Verify((p) => p.ShareInstance(It.IsNotNull(), "Name", sharedName), Times.Once()); - } + [WindowsOnlyFact] + public static void Share_Throws_If_SqlLocalDbEception_Is_Thrown() + { + // Act + var innerException = new SqlLocalDbException( + "It broke", + 123, + "Name"); - [WindowsOnlyFact] - public static void Share_Throws_If_SqlLocalDbEception_Is_Thrown() - { - // Act - var innerException = new SqlLocalDbException( - "It broke", - 123, - "Name"); + var mock = new Mock(); - var mock = new Mock(); + mock.Setup((p) => p.ShareInstance(It.IsAny(), It.IsAny(), It.IsAny())) + .Throws(innerException); - mock.Setup((p) => p.ShareInstance(It.IsAny(), It.IsAny(), It.IsAny())) - .Throws(innerException); + ISqlLocalDbInstanceInfo instance = CreateInstance(); + ISqlLocalDbApi api = mock.Object; - ISqlLocalDbInstanceInfo instance = CreateInstance(); - ISqlLocalDbApi api = mock.Object; + var target = new SqlLocalDbInstanceManager(instance, api); - var target = new SqlLocalDbInstanceManager(instance, api); + var exception = Assert.Throws(() => target.Share("SharedName")); - var exception = Assert.Throws(() => target.Share("SharedName")); + exception.ErrorCode.ShouldBe(123); + exception.InstanceName.ShouldBe("Name"); + exception.Message.ShouldBe("Failed to share SQL LocalDB instance 'Name'."); + exception.InnerException.ShouldBeSameAs(innerException); + } - exception.ErrorCode.ShouldBe(123); - exception.InstanceName.ShouldBe("Name"); - exception.Message.ShouldBe("Failed to share SQL LocalDB instance 'Name'."); - exception.InnerException.ShouldBeSameAs(innerException); - } + [Fact] + public void Constructor_Validates_Arguments() + { + // Act + ISqlLocalDbInstanceInfo instance = CreateInstance(); + var api = Mock.Of(); - [Fact] - public void Constructor_Validates_Arguments() - { - // Act - ISqlLocalDbInstanceInfo instance = CreateInstance(); - var api = Mock.Of(); + // Act and Assert + Assert.Throws("instance", () => new SqlLocalDbInstanceManager(null!, api)); + Assert.Throws("api", () => new SqlLocalDbInstanceManager(instance, null!)); + } - // Act and Assert - Assert.Throws("instance", () => new SqlLocalDbInstanceManager(null!, api)); - Assert.Throws("api", () => new SqlLocalDbInstanceManager(instance, null!)); - } + [Fact] + public void Constructor_Initializes_Properties() + { + // Act + ISqlLocalDbInstanceInfo instance = CreateInstance(); + var api = Mock.Of(); - [Fact] - public void Constructor_Initializes_Properties() - { - // Act - ISqlLocalDbInstanceInfo instance = CreateInstance(); - var api = Mock.Of(); + // Act + var actual = new SqlLocalDbInstanceManager(instance, api); - // Act - var actual = new SqlLocalDbInstanceManager(instance, api); + // Assert + actual.Name.ShouldBe("Name"); + actual.NamedPipe.ShouldBe("NamedPipe"); + } - // Assert - actual.Name.ShouldBe("Name"); - actual.NamedPipe.ShouldBe("NamedPipe"); - } + [Fact] + public void Share_Throws_If_SharedName_Is_Null() + { + // Act + ISqlLocalDbInstanceInfo instance = CreateInstance(); + var api = Mock.Of(); + var target = new SqlLocalDbInstanceManager(instance, api); - [Fact] - public void Share_Throws_If_SharedName_Is_Null() - { - // Act - ISqlLocalDbInstanceInfo instance = CreateInstance(); - var api = Mock.Of(); - var target = new SqlLocalDbInstanceManager(instance, api); + Assert.Throws("sharedName", () => target.Share(null!)); + } - Assert.Throws("sharedName", () => target.Share(null!)); - } + [Fact] + public void Start_Starts_Instance() + { + // Act + var mock = new Mock(); + ISqlLocalDbInstanceInfo instance = CreateInstance(); + ISqlLocalDbApi api = mock.Object; - [Fact] - public void Start_Starts_Instance() - { - // Act - var mock = new Mock(); - ISqlLocalDbInstanceInfo instance = CreateInstance(); - ISqlLocalDbApi api = mock.Object; + var target = new SqlLocalDbInstanceManager(instance, api); - var target = new SqlLocalDbInstanceManager(instance, api); + // Act + target.Start(); - // Act - target.Start(); + // Assert + mock.Verify((p) => p.StartInstance("Name"), Times.Once()); + } - // Assert - mock.Verify((p) => p.StartInstance("Name"), Times.Once()); - } + [Fact] + public void Start_Throws_If_SqlLocalDbEception_Is_Thrown() + { + // Act + var innerException = new SqlLocalDbException( + "It broke", + 123, + "Name"); - [Fact] - public void Start_Throws_If_SqlLocalDbEception_Is_Thrown() - { - // Act - var innerException = new SqlLocalDbException( - "It broke", - 123, - "Name"); + var mock = new Mock(); - var mock = new Mock(); + mock.Setup((p) => p.StartInstance(It.IsAny())) + .Throws(innerException); - mock.Setup((p) => p.StartInstance(It.IsAny())) - .Throws(innerException); + ISqlLocalDbInstanceInfo instance = CreateInstance(); + ISqlLocalDbApi api = mock.Object; - ISqlLocalDbInstanceInfo instance = CreateInstance(); - ISqlLocalDbApi api = mock.Object; + var target = new SqlLocalDbInstanceManager(instance, api); - var target = new SqlLocalDbInstanceManager(instance, api); + var exception = Assert.Throws(() => target.Start()); - var exception = Assert.Throws(() => target.Start()); + exception.ErrorCode.ShouldBe(123); + exception.InstanceName.ShouldBe("Name"); + exception.Message.ShouldBe("Failed to start SQL LocalDB instance 'Name'."); + exception.InnerException.ShouldBeSameAs(innerException); + } - exception.ErrorCode.ShouldBe(123); - exception.InstanceName.ShouldBe("Name"); - exception.Message.ShouldBe("Failed to start SQL LocalDB instance 'Name'."); - exception.InnerException.ShouldBeSameAs(innerException); - } + [Fact] + public void Stop_Stops_Instance() + { + // Act + var mock = new Mock(); + ISqlLocalDbInstanceInfo instance = CreateInstance(); + ISqlLocalDbApi api = mock.Object; - [Fact] - public void Stop_Stops_Instance() - { - // Act - var mock = new Mock(); - ISqlLocalDbInstanceInfo instance = CreateInstance(); - ISqlLocalDbApi api = mock.Object; + var target = new SqlLocalDbInstanceManager(instance, api); - var target = new SqlLocalDbInstanceManager(instance, api); + // Act + target.Stop(); - // Act - target.Stop(); + // Assert + mock.Verify((p) => p.StopInstance("Name", null), Times.Once()); + } - // Assert - mock.Verify((p) => p.StopInstance("Name", null), Times.Once()); - } + [Fact] + public void Stop_Throws_If_SqlLocalDbEception_Is_Thrown() + { + // Act + var innerException = new SqlLocalDbException( + "It broke", + 123, + "Name"); - [Fact] - public void Stop_Throws_If_SqlLocalDbEception_Is_Thrown() - { - // Act - var innerException = new SqlLocalDbException( - "It broke", - 123, - "Name"); + var mock = new Mock(); - var mock = new Mock(); + mock.Setup((p) => p.StopInstance(It.IsAny(), It.IsAny())) + .Throws(innerException); - mock.Setup((p) => p.StopInstance(It.IsAny(), It.IsAny())) - .Throws(innerException); + ISqlLocalDbInstanceInfo instance = CreateInstance(); + ISqlLocalDbApi api = mock.Object; - ISqlLocalDbInstanceInfo instance = CreateInstance(); - ISqlLocalDbApi api = mock.Object; + var target = new SqlLocalDbInstanceManager(instance, api); - var target = new SqlLocalDbInstanceManager(instance, api); + var exception = Assert.Throws(() => target.Stop()); - var exception = Assert.Throws(() => target.Stop()); + exception.ErrorCode.ShouldBe(123); + exception.InstanceName.ShouldBe("Name"); + exception.Message.ShouldBe("Failed to stop SQL LocalDB instance 'Name'."); + exception.InnerException.ShouldBeSameAs(innerException); + } - exception.ErrorCode.ShouldBe(123); - exception.InstanceName.ShouldBe("Name"); - exception.Message.ShouldBe("Failed to stop SQL LocalDB instance 'Name'."); - exception.InnerException.ShouldBeSameAs(innerException); - } + [Fact] + public void Unshare_Unshares_Instance() + { + // Act + var mock = new Mock(); + ISqlLocalDbInstanceInfo instance = CreateInstance(); + ISqlLocalDbApi api = mock.Object; - [Fact] - public void Unshare_Unshares_Instance() - { - // Act - var mock = new Mock(); - ISqlLocalDbInstanceInfo instance = CreateInstance(); - ISqlLocalDbApi api = mock.Object; + var target = new SqlLocalDbInstanceManager(instance, api); - var target = new SqlLocalDbInstanceManager(instance, api); + // Act + target.Unshare(); - // Act - target.Unshare(); + // Assert + mock.Verify((p) => p.UnshareInstance("Name"), Times.Once()); + } - // Assert - mock.Verify((p) => p.UnshareInstance("Name"), Times.Once()); - } + [Fact] + public void Unshare_Throws_If_SqlLocalDbEception_Is_Thrown() + { + // Act + var innerException = new SqlLocalDbException( + "It broke", + 123, + "Name"); - [Fact] - public void Unshare_Throws_If_SqlLocalDbEception_Is_Thrown() - { - // Act - var innerException = new SqlLocalDbException( - "It broke", - 123, - "Name"); + var mock = new Mock(); - var mock = new Mock(); + mock.Setup((p) => p.UnshareInstance(It.IsAny())) + .Throws(innerException); - mock.Setup((p) => p.UnshareInstance(It.IsAny())) - .Throws(innerException); + ISqlLocalDbInstanceInfo instance = CreateInstance(); + ISqlLocalDbApi api = mock.Object; - ISqlLocalDbInstanceInfo instance = CreateInstance(); - ISqlLocalDbApi api = mock.Object; + var target = new SqlLocalDbInstanceManager(instance, api); - var target = new SqlLocalDbInstanceManager(instance, api); + var exception = Assert.Throws(() => target.Unshare()); - var exception = Assert.Throws(() => target.Unshare()); + exception.ErrorCode.ShouldBe(123); + exception.InstanceName.ShouldBe("Name"); + exception.Message.ShouldBe("Failed to stop sharing SQL LocalDB instance 'Name'."); + exception.InnerException.ShouldBeSameAs(innerException); + } - exception.ErrorCode.ShouldBe(123); - exception.InstanceName.ShouldBe("Name"); - exception.Message.ShouldBe("Failed to stop sharing SQL LocalDB instance 'Name'."); - exception.InnerException.ShouldBeSameAs(innerException); - } + [RunAsAdminFact] + public void Manager_Shares_And_Unshares_Instance() + { + // Act + string instanceName = Guid.NewGuid().ToString(); + string sharedName = Guid.NewGuid().ToString(); - [RunAsAdminFact] - public void Manager_Shares_And_Unshares_Instance() - { - // Act - string instanceName = Guid.NewGuid().ToString(); - string sharedName = Guid.NewGuid().ToString(); + using var api = new SqlLocalDbApi(_loggerFactory); + api.CreateInstance(instanceName); - using var api = new SqlLocalDbApi(_loggerFactory); - api.CreateInstance(instanceName); + try + { + api.StartInstance(instanceName); try { - api.StartInstance(instanceName); + var instance = api.GetInstanceInfo(instanceName); - try - { - var instance = api.GetInstanceInfo(instanceName); + var manager = new SqlLocalDbInstanceManager(instance, api); - var manager = new SqlLocalDbInstanceManager(instance, api); + // Act + manager.Share(sharedName); - // Act - manager.Share(sharedName); + // Assert + instance.IsShared.ShouldBeTrue(); - // Assert - instance.IsShared.ShouldBeTrue(); + // Act + manager.Unshare(); - // Act - manager.Unshare(); - - // Assert - instance.IsShared.ShouldBeFalse(); - } - catch (Exception) - { - api.StopInstance(instanceName); - throw; - } + // Assert + instance.IsShared.ShouldBeFalse(); } catch (Exception) { - api.DeleteInstanceInternal(instanceName, throwIfNotFound: false, deleteFiles: true); + api.StopInstance(instanceName); throw; } } - - private static ISqlLocalDbInstanceInfo CreateInstance() + catch (Exception) { - var mock = new Mock(); + api.DeleteInstanceInternal(instanceName, throwIfNotFound: false, deleteFiles: true); + throw; + } + } - mock.Setup((p) => p.Name).Returns("Name"); - mock.Setup((p) => p.NamedPipe).Returns("NamedPipe"); + private static ISqlLocalDbInstanceInfo CreateInstance() + { + var mock = new Mock(); - return mock.Object; - } + mock.Setup((p) => p.Name).Returns("Name"); + mock.Setup((p) => p.NamedPipe).Returns("NamedPipe"); + + return mock.Object; } } diff --git a/tests/SqlLocalDb.Tests/SqlLocalDbOptionsTests.cs b/tests/SqlLocalDb.Tests/SqlLocalDbOptionsTests.cs index 7df5659b..557fdf8c 100644 --- a/tests/SqlLocalDb.Tests/SqlLocalDbOptionsTests.cs +++ b/tests/SqlLocalDb.Tests/SqlLocalDbOptionsTests.cs @@ -1,35 +1,34 @@ // Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -namespace MartinCostello.SqlLocalDb +namespace MartinCostello.SqlLocalDb; + +public static class SqlLocalDbOptionsTests { - public static class SqlLocalDbOptionsTests + [Fact] + public static void SqlLocalDbOptions_Defaults_Are_Correct() { - [Fact] - public static void SqlLocalDbOptions_Defaults_Are_Correct() - { - // Act - var actual = new SqlLocalDbOptions(); + // Act + var actual = new SqlLocalDbOptions(); - // Assert - actual.AutomaticallyDeleteInstanceFiles.ShouldBeFalse(); - actual.Language.ShouldBeNull(); - actual.NativeApiOverrideVersion.ShouldBe(string.Empty); - actual.StopOptions.ShouldBe(StopInstanceOptions.None); - actual.StopTimeout.ShouldBe(TimeSpan.FromMinutes(1)); - } + // Assert + actual.AutomaticallyDeleteInstanceFiles.ShouldBeFalse(); + actual.Language.ShouldBeNull(); + actual.NativeApiOverrideVersion.ShouldBe(string.Empty); + actual.StopOptions.ShouldBe(StopInstanceOptions.None); + actual.StopTimeout.ShouldBe(TimeSpan.FromMinutes(1)); + } - [Fact] - public static void SqlLocalDbOptions_LanguageId_Returns_The_LCID() + [Fact] + public static void SqlLocalDbOptions_LanguageId_Returns_The_LCID() + { + // Act + var actual = new SqlLocalDbOptions() { - // Act - var actual = new SqlLocalDbOptions() - { - Language = CultureInfo.GetCultureInfo("de-DE"), - }; + Language = CultureInfo.GetCultureInfo("de-DE"), + }; - // Assert - actual.LanguageId.ShouldBeGreaterThan(0); - } + // Assert + actual.LanguageId.ShouldBeGreaterThan(0); } } diff --git a/tests/SqlLocalDb.Tests/SqlLocalDbServiceCollectionExtensionsTests.cs b/tests/SqlLocalDb.Tests/SqlLocalDbServiceCollectionExtensionsTests.cs index 3925dcbd..e9bee32b 100644 --- a/tests/SqlLocalDb.Tests/SqlLocalDbServiceCollectionExtensionsTests.cs +++ b/tests/SqlLocalDb.Tests/SqlLocalDbServiceCollectionExtensionsTests.cs @@ -4,147 +4,146 @@ using Microsoft.Extensions.DependencyInjection; using Moq; -namespace MartinCostello.SqlLocalDb +namespace MartinCostello.SqlLocalDb; + +public static class SqlLocalDbServiceCollectionExtensionsTests { - public static class SqlLocalDbServiceCollectionExtensionsTests + [Fact] + public static void AddSqlLocalDB_Validates_Parameters() { - [Fact] - public static void AddSqlLocalDB_Validates_Parameters() - { - // Arrange - IServiceCollection? services = Mock.Of(); + // Arrange + IServiceCollection? services = Mock.Of(); - SqlLocalDbOptions? options = null; - Action? configureAction = null; - Func? configureFunc = null; + SqlLocalDbOptions? options = null; + Action? configureAction = null; + Func? configureFunc = null; - // Act and Assert - Assert.Throws("options", () => services.AddSqlLocalDB(options!)); - Assert.Throws("configure", () => services.AddSqlLocalDB(configureAction!)); - Assert.Throws("configure", () => services.AddSqlLocalDB(configureFunc!)); + // Act and Assert + Assert.Throws("options", () => services.AddSqlLocalDB(options!)); + Assert.Throws("configure", () => services.AddSqlLocalDB(configureAction!)); + Assert.Throws("configure", () => services.AddSqlLocalDB(configureFunc!)); - services = null; + services = null; - // Act and Assert - Assert.Throws("services", () => services!.AddSqlLocalDB()); - Assert.Throws("services", () => services!.AddSqlLocalDB(options!)); - Assert.Throws("services", () => services!.AddSqlLocalDB(configureAction!)); - Assert.Throws("services", () => services!.AddSqlLocalDB(configureFunc!)); - } + // Act and Assert + Assert.Throws("services", () => services!.AddSqlLocalDB()); + Assert.Throws("services", () => services!.AddSqlLocalDB(options!)); + Assert.Throws("services", () => services!.AddSqlLocalDB(configureAction!)); + Assert.Throws("services", () => services!.AddSqlLocalDB(configureFunc!)); + } - [Fact] - public static void AddSqlLocalDB_Registers_Services_Using_Defaults() - { - // Arrange - IServiceCollection services = CreateServiceCollection(); + [Fact] + public static void AddSqlLocalDB_Registers_Services_Using_Defaults() + { + // Arrange + IServiceCollection services = CreateServiceCollection(); - // Act - services.AddSqlLocalDB(); + // Act + services.AddSqlLocalDB(); - // Assert - IServiceProvider provider = services.BuildServiceProvider(); + // Assert + IServiceProvider provider = services.BuildServiceProvider(); - var options = provider.GetRequiredService(); - options.ShouldNotBeNull(); + var options = provider.GetRequiredService(); + options.ShouldNotBeNull(); - var localDB = provider.GetRequiredService(); - localDB.ShouldNotBeNull(); - localDB.ShouldBeOfType(); - } + var localDB = provider.GetRequiredService(); + localDB.ShouldNotBeNull(); + localDB.ShouldBeOfType(); + } - [Fact] - public static void AddSqlLocalDB_Registers_Services_Using_Options() + [Fact] + public static void AddSqlLocalDB_Registers_Services_Using_Options() + { + // Arrange + var options = new SqlLocalDbOptions() { - // Arrange - var options = new SqlLocalDbOptions() - { - StopOptions = (StopInstanceOptions)int.MinValue, - }; + StopOptions = (StopInstanceOptions)int.MinValue, + }; - IServiceCollection services = CreateServiceCollection(); + IServiceCollection services = CreateServiceCollection(); - // Act - services.AddSqlLocalDB(options); + // Act + services.AddSqlLocalDB(options); - // Assert - IServiceProvider provider = services.BuildServiceProvider(); + // Assert + IServiceProvider provider = services.BuildServiceProvider(); - var actualOptions = provider.GetRequiredService(); - options.ShouldBeSameAs(actualOptions); + var actualOptions = provider.GetRequiredService(); + options.ShouldBeSameAs(actualOptions); - var localDB = provider.GetRequiredService(); - localDB.ShouldNotBeNull(); - localDB.ShouldBeOfType(); - } - - [Fact] - public static void AddSqlLocalDB_Registers_Services_Using_Action() - { - // Arrange - IServiceCollection services = CreateServiceCollection(); + var localDB = provider.GetRequiredService(); + localDB.ShouldNotBeNull(); + localDB.ShouldBeOfType(); + } - // Act - services.AddSqlLocalDB((p) => p.StopOptions = (StopInstanceOptions)int.MinValue); + [Fact] + public static void AddSqlLocalDB_Registers_Services_Using_Action() + { + // Arrange + IServiceCollection services = CreateServiceCollection(); - // Assert - IServiceProvider provider = services.BuildServiceProvider(); + // Act + services.AddSqlLocalDB((p) => p.StopOptions = (StopInstanceOptions)int.MinValue); - var options = provider.GetRequiredService(); - options.ShouldNotBeNull(); - options.StopOptions.ShouldBe((StopInstanceOptions)int.MinValue); + // Assert + IServiceProvider provider = services.BuildServiceProvider(); - var localDB = provider.GetRequiredService(); - localDB.ShouldNotBeNull(); - localDB.ShouldBeOfType(); - } + var options = provider.GetRequiredService(); + options.ShouldNotBeNull(); + options.StopOptions.ShouldBe((StopInstanceOptions)int.MinValue); - [Fact] - public static void AddSqlLocalDB_Registers_Services_Using_Function() - { - // Arrange - IServiceCollection services = CreateServiceCollection(); + var localDB = provider.GetRequiredService(); + localDB.ShouldNotBeNull(); + localDB.ShouldBeOfType(); + } - // Act - services.AddSqlLocalDB((p) => new SqlLocalDbOptions() { StopOptions = (StopInstanceOptions)int.MinValue }); + [Fact] + public static void AddSqlLocalDB_Registers_Services_Using_Function() + { + // Arrange + IServiceCollection services = CreateServiceCollection(); - // Assert - IServiceProvider provider = services.BuildServiceProvider(); + // Act + services.AddSqlLocalDB((p) => new SqlLocalDbOptions() { StopOptions = (StopInstanceOptions)int.MinValue }); - var options = provider.GetRequiredService(); - options.ShouldNotBeNull(); - options.StopOptions.ShouldBe((StopInstanceOptions)int.MinValue); + // Assert + IServiceProvider provider = services.BuildServiceProvider(); - var localDB = provider.GetRequiredService(); - localDB.ShouldNotBeNull(); - localDB.ShouldBeOfType(); - } + var options = provider.GetRequiredService(); + options.ShouldNotBeNull(); + options.StopOptions.ShouldBe((StopInstanceOptions)int.MinValue); - [Fact] - public static void AddSqlLocalDB_Does_Not_Overwrite_Existing_Services() - { - // Arrange - IServiceCollection services = CreateServiceCollection(); + var localDB = provider.GetRequiredService(); + localDB.ShouldNotBeNull(); + localDB.ShouldBeOfType(); + } - var existingOptions = new SqlLocalDbOptions(); - var existingLocalDB = Mock.Of(); + [Fact] + public static void AddSqlLocalDB_Does_Not_Overwrite_Existing_Services() + { + // Arrange + IServiceCollection services = CreateServiceCollection(); - services.AddTransient((_) => existingOptions); - services.AddTransient((_) => existingLocalDB); + var existingOptions = new SqlLocalDbOptions(); + var existingLocalDB = Mock.Of(); - // Act - services.AddSqlLocalDB(); + services.AddTransient((_) => existingOptions); + services.AddTransient((_) => existingLocalDB); - // Assert - IServiceProvider provider = services.BuildServiceProvider(); + // Act + services.AddSqlLocalDB(); - var actualOptions = provider.GetRequiredService(); - actualOptions.ShouldBeSameAs(existingOptions); + // Assert + IServiceProvider provider = services.BuildServiceProvider(); - var actualLocalDB = provider.GetRequiredService(); - actualLocalDB.ShouldBeSameAs(existingLocalDB); - } + var actualOptions = provider.GetRequiredService(); + actualOptions.ShouldBeSameAs(existingOptions); - private static IServiceCollection CreateServiceCollection() - => new ServiceCollection().AddLogging(); + var actualLocalDB = provider.GetRequiredService(); + actualLocalDB.ShouldBeSameAs(existingLocalDB); } + + private static IServiceCollection CreateServiceCollection() + => new ServiceCollection().AddLogging(); } diff --git a/tests/SqlLocalDb.Tests/SqlLocalDbVersionInfoTests.cs b/tests/SqlLocalDb.Tests/SqlLocalDbVersionInfoTests.cs index 24def8a4..2bc0e465 100644 --- a/tests/SqlLocalDb.Tests/SqlLocalDbVersionInfoTests.cs +++ b/tests/SqlLocalDb.Tests/SqlLocalDbVersionInfoTests.cs @@ -1,95 +1,94 @@ // Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -namespace MartinCostello.SqlLocalDb +namespace MartinCostello.SqlLocalDb; + +public static class SqlLocalDbVersionInfoTests { - public static class SqlLocalDbVersionInfoTests + [Fact] + public static void Update_Copies_State_From_Other_Instance() { - [Fact] - public static void Update_Copies_State_From_Other_Instance() + // Arrange + var other = new SqlLocalDbVersionInfo() { - // Arrange - var other = new SqlLocalDbVersionInfo() - { - Exists = true, - Name = "OtherName", - Version = new Version(2, 1), - }; + Exists = true, + Name = "OtherName", + Version = new Version(2, 1), + }; - var actual = new SqlLocalDbVersionInfo() - { - Exists = false, - Name = "Name", - Version = new Version(2, 0), - }; + var actual = new SqlLocalDbVersionInfo() + { + Exists = false, + Name = "Name", + Version = new Version(2, 0), + }; - // Act - actual.Update(other); + // Act + actual.Update(other); - // Assert - actual.Exists.ShouldBe(other.Exists); - actual.Name.ShouldBe(other.Name); - actual.Version.ShouldBe(other.Version); - } + // Assert + actual.Exists.ShouldBe(other.Exists); + actual.Name.ShouldBe(other.Name); + actual.Version.ShouldBe(other.Version); + } - [Fact] - public static void Update_Does_Not_Copy_State_If_Other_Is_Null() - { - // Arrange - ISqlLocalDbVersionInfo? other = null; + [Fact] + public static void Update_Does_Not_Copy_State_If_Other_Is_Null() + { + // Arrange + ISqlLocalDbVersionInfo? other = null; - var actual = new SqlLocalDbVersionInfo() - { - Exists = false, - Name = "Name", - Version = new Version(2, 0), - }; + var actual = new SqlLocalDbVersionInfo() + { + Exists = false, + Name = "Name", + Version = new Version(2, 0), + }; - // Act - actual.Update(other!); + // Act + actual.Update(other!); - // Assert - actual.Exists.ShouldBeFalse(); - actual.Name.ShouldBe("Name"); - actual.Version.ShouldBe(new Version(2, 0)); - } + // Assert + actual.Exists.ShouldBeFalse(); + actual.Name.ShouldBe("Name"); + actual.Version.ShouldBe(new Version(2, 0)); + } - [Fact] - public static void Update_Does_Not_Copy_State_If_Other_Is_Self() + [Fact] + public static void Update_Does_Not_Copy_State_If_Other_Is_Self() + { + // Arrange + var actual = new SqlLocalDbVersionInfo() { - // Arrange - var actual = new SqlLocalDbVersionInfo() - { - Exists = false, - Name = "Name", - Version = new Version(2, 0), - }; + Exists = false, + Name = "Name", + Version = new Version(2, 0), + }; - // Act - actual.Update(actual); + // Act + actual.Update(actual); - // Assert - actual.Exists.ShouldBeFalse(); - actual.Name.ShouldBe("Name"); - actual.Version.ShouldBe(new Version(2, 0)); - } + // Assert + actual.Exists.ShouldBeFalse(); + actual.Name.ShouldBe("Name"); + actual.Version.ShouldBe(new Version(2, 0)); + } - [Fact] - public static void ToString_Returns_The_Name() + [Fact] + public static void ToString_Returns_The_Name() + { + // Arrange + var version = new SqlLocalDbVersionInfo() { - // Arrange - var version = new SqlLocalDbVersionInfo() - { - Exists = false, - Name = "Name", - Version = new Version(2, 0), - }; + Exists = false, + Name = "Name", + Version = new Version(2, 0), + }; - // Act and Assert - string actual = version.ToString(); + // Act and Assert + string actual = version.ToString(); - // Assert - actual.ShouldBe("Name"); - } + // Assert + actual.ShouldBe("Name"); } } diff --git a/tests/SqlLocalDb.Tests/WindowsCIOnlyFactAttribute.cs b/tests/SqlLocalDb.Tests/WindowsCIOnlyFactAttribute.cs index 6884d08a..da817230 100644 --- a/tests/SqlLocalDb.Tests/WindowsCIOnlyFactAttribute.cs +++ b/tests/SqlLocalDb.Tests/WindowsCIOnlyFactAttribute.cs @@ -1,23 +1,22 @@ // Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -namespace MartinCostello.SqlLocalDb +namespace MartinCostello.SqlLocalDb; + +/// +/// Attribute that is applied to a method to indicate that it is a fact that should be run by the +/// test runner if the current operating system is Windows. This class cannot be inherited. +/// +[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] +public sealed class WindowsCIOnlyFactAttribute : FactAttribute { - /// - /// Attribute that is applied to a method to indicate that it is a fact that should be run by the - /// test runner if the current operating system is Windows. This class cannot be inherited. - /// - [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] - public sealed class WindowsCIOnlyFactAttribute : FactAttribute + public WindowsCIOnlyFactAttribute() + : base() { - public WindowsCIOnlyFactAttribute() - : base() - { - bool isWindowsCI = - OperatingSystem.IsWindows() && - !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("CI")); + bool isWindowsCI = + OperatingSystem.IsWindows() && + !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("CI")); - Skip = isWindowsCI ? string.Empty : "This test can only be run on Windows CI."; - } + Skip = isWindowsCI ? string.Empty : "This test can only be run on Windows CI."; } } diff --git a/tests/SqlLocalDb.Tests/WindowsOnlyFactAttribute.cs b/tests/SqlLocalDb.Tests/WindowsOnlyFactAttribute.cs index d0a5bd68..2a7c42a4 100644 --- a/tests/SqlLocalDb.Tests/WindowsOnlyFactAttribute.cs +++ b/tests/SqlLocalDb.Tests/WindowsOnlyFactAttribute.cs @@ -3,26 +3,25 @@ using Xunit.Sdk; -namespace MartinCostello.SqlLocalDb +namespace MartinCostello.SqlLocalDb; + +/// +/// Attribute that is applied to a method to indicate that it is a fact that should be run by the +/// test runner if the current operating system is Windows. This class cannot be inherited. +/// +[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] +[XunitTestCaseDiscoverer("MartinCostello.SqlLocalDb.RetryFactDiscoverer", "MartinCostello.SqlLocalDb.Tests")] +public sealed class WindowsOnlyFactAttribute : FactAttribute { - /// - /// Attribute that is applied to a method to indicate that it is a fact that should be run by the - /// test runner if the current operating system is Windows. This class cannot be inherited. - /// - [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] - [XunitTestCaseDiscoverer("MartinCostello.SqlLocalDb.RetryFactDiscoverer", "MartinCostello.SqlLocalDb.Tests")] - public sealed class WindowsOnlyFactAttribute : FactAttribute + public WindowsOnlyFactAttribute() + : base() { - public WindowsOnlyFactAttribute() - : base() - { - Skip = OperatingSystem.IsWindows() ? string.Empty : "This test can only be run on Windows."; - } - - /// - /// Gets or sets the number of retries allowed for a failed test. - /// If unset (or set less than 1), will default to 3 attempts. - /// - public int MaxRetries { get; set; } + Skip = OperatingSystem.IsWindows() ? string.Empty : "This test can only be run on Windows."; } + + /// + /// Gets or sets the number of retries allowed for a failed test. + /// If unset (or set less than 1), will default to 3 attempts. + /// + public int MaxRetries { get; set; } } From 0832ff54e49b4b52b2bcf89ddbda90944104a1c1 Mon Sep 17 00:00:00 2001 From: martincostello Date: Sun, 22 Aug 2021 10:21:19 +0100 Subject: [PATCH 15/29] Update StyleCop.Analyzers Update StyleCop.Analyzers to the latest release. Fix issues found with C#9 and C#10 code style. --- Directory.Packages.props | 2 +- src/SqlLocalDb/SqlLocalDbApi.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 9c4fde60..67fececa 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -16,7 +16,7 @@ - + diff --git a/src/SqlLocalDb/SqlLocalDbApi.cs b/src/SqlLocalDb/SqlLocalDbApi.cs index 298441fc..885fd2d3 100644 --- a/src/SqlLocalDb/SqlLocalDbApi.cs +++ b/src/SqlLocalDb/SqlLocalDbApi.cs @@ -1297,7 +1297,7 @@ private static string[] MarshalStringArray(IntPtr ptr, int length, int count) { // Determine the offset of the element, and get the string from the array IntPtr offset = new IntPtr(ptr.ToInt64() + (length * i)); - result[i] = Marshal.PtrToStringAuto(offset) !; + result[i] = Marshal.PtrToStringAuto(offset)!; } return result; @@ -1314,7 +1314,7 @@ private static string[] MarshalStringArray(IntPtr ptr, int length, int count) private static T MarshalStruct(IntPtr ptr) where T : struct { - return (T)Marshal.PtrToStructure(ptr, typeof(T)) !; + return (T)Marshal.PtrToStructure(ptr, typeof(T))!; } /// From 631a4eccd406f689cff026aa1caf51301d919356 Mon Sep 17 00:00:00 2001 From: martincostello Date: Sun, 22 Aug 2021 10:21:41 +0100 Subject: [PATCH 16/29] Suppress CA2254 They only vary due to localisation, so it's just noise. --- src/SqlLocalDb/MartinCostello.SqlLocalDb.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SqlLocalDb/MartinCostello.SqlLocalDb.csproj b/src/SqlLocalDb/MartinCostello.SqlLocalDb.csproj index e2ae7b8a..00f087d6 100644 --- a/src/SqlLocalDb/MartinCostello.SqlLocalDb.csproj +++ b/src/SqlLocalDb/MartinCostello.SqlLocalDb.csproj @@ -4,7 +4,7 @@ SQL LocalDB Wrapper A .NET assembly providing interop with the SQL LocalDB native API from managed code using .NET APIs. true - $(NoWarn);CA2235 + $(NoWarn);CA2235;CA2254 Library MartinCostello.SqlLocalDb 3.0.0 From de53352fe0ed6e5653f1547d6f92a413e08749e6 Mon Sep 17 00:00:00 2001 From: martincostello Date: Sun, 22 Aug 2021 10:27:59 +0100 Subject: [PATCH 17/29] Simplify new and using expressions Simplify new and using expressions as suggested by Visual Studio. --- src/SqlLocalDb/EventIds.cs | 112 +++++++++--------- src/SqlLocalDb/Interop/LocalDbInstanceApi.cs | 4 +- src/SqlLocalDb/Interop/LocalDbInstanceInfo.cs | 2 +- src/SqlLocalDb/Interop/LocalDbVersionInfo.cs | 2 +- src/SqlLocalDb/SqlLocalDbApi.cs | 4 +- src/TestApp/Program.cs | 4 +- tests/SqlLocalDb.Tests/DelayedMessageBus.cs | 2 +- tests/SqlLocalDb.Tests/Examples.cs | 73 +++++------- tests/SqlLocalDb.Tests/NotInParallelTests.cs | 33 +++--- .../RunAsAdminFactAttribute.cs | 9 +- tests/SqlLocalDb.Tests/SqlLocalDbApiTests.cs | 2 +- 11 files changed, 118 insertions(+), 129 deletions(-) diff --git a/src/SqlLocalDb/EventIds.cs b/src/SqlLocalDb/EventIds.cs index 59c80500..5e978d4d 100644 --- a/src/SqlLocalDb/EventIds.cs +++ b/src/SqlLocalDb/EventIds.cs @@ -15,282 +15,282 @@ internal static class EventIds /// /// The for when the SQL LocalDB Instance API is loaded. This field is read-only. /// - internal static readonly EventId NativeApiLoaded = new EventId(++Id, nameof(NativeApiLoaded)); + internal static readonly EventId NativeApiLoaded = new(++Id, nameof(NativeApiLoaded)); /// /// The for when the SQL LocalDB Instance API fails to load. This field is read-only. /// - internal static readonly EventId NativeApiLoadFailed = new EventId(++Id, nameof(NativeApiLoadFailed)); + internal static readonly EventId NativeApiLoadFailed = new(++Id, nameof(NativeApiLoadFailed)); /// /// The for when the SQL LocalDB Instance API is not loaded. This field is read-only. /// - internal static readonly EventId NativeApiNotLoaded = new EventId(++Id, nameof(NativeApiNotLoaded)); + internal static readonly EventId NativeApiNotLoaded = new(++Id, nameof(NativeApiNotLoaded)); /// /// The for when the SQL LocalDB Instance API version is overridden. This field is read-only. /// - internal static readonly EventId NativeApiVersionOverriddenByUser = new EventId(++Id, nameof(NativeApiVersionOverriddenByUser)); + internal static readonly EventId NativeApiVersionOverriddenByUser = new(++Id, nameof(NativeApiVersionOverriddenByUser)); /// /// The for when the SQL LocalDB Instance API version specified as an override cannot be found. This field is read-only. /// - internal static readonly EventId NativeApiVersionOverrideNotFound = new EventId(++Id, nameof(NativeApiVersionOverrideNotFound)); + internal static readonly EventId NativeApiVersionOverrideNotFound = new(++Id, nameof(NativeApiVersionOverrideNotFound)); /// /// The for when the SQL LocalDB Instance API cannot be found. This field is read-only. /// - internal static readonly EventId NoNativeApiFound = new EventId(++Id, nameof(NoNativeApiFound)); + internal static readonly EventId NoNativeApiFound = new(++Id, nameof(NoNativeApiFound)); /// /// The for when the SQL LocalDB Instance API path configured in the registry cannot be found. This field is read-only. /// - internal static readonly EventId NativeApiPathNotFound = new EventId(++Id, nameof(NativeApiPathNotFound)); + internal static readonly EventId NativeApiPathNotFound = new(++Id, nameof(NativeApiPathNotFound)); /// /// The for when a native function export from the SQL LocalDB Instance API cannot be found. This field is read-only. /// - internal static readonly EventId NativeFunctionNotFound = new EventId(++Id, nameof(NativeFunctionNotFound)); + internal static readonly EventId NativeFunctionNotFound = new(++Id, nameof(NativeFunctionNotFound)); /// /// The for when the SQL LocalDB Instance API is not installed. This field is read-only. /// - internal static readonly EventId NotInstalled = new EventId(++Id, nameof(NotInstalled)); + internal static readonly EventId NotInstalled = new(++Id, nameof(NotInstalled)); /// /// The for when a SQL LocalDB instance is being created. This field is read-only. /// - internal static readonly EventId CreatingInstance = new EventId(++Id, nameof(CreatingInstance)); + internal static readonly EventId CreatingInstance = new(++Id, nameof(CreatingInstance)); /// /// The for when creating a SQL LocalDB instance fails. This field is read-only. /// - internal static readonly EventId CreatingInstanceFailed = new EventId(++Id, nameof(CreatingInstanceFailed)); + internal static readonly EventId CreatingInstanceFailed = new(++Id, nameof(CreatingInstanceFailed)); /// /// The for when a SQL LocalDB instance has been created. This field is read-only. /// - internal static readonly EventId CreatedInstance = new EventId(++Id, nameof(CreatedInstance)); + internal static readonly EventId CreatedInstance = new(++Id, nameof(CreatedInstance)); /// /// The for when a SQL LocalDB instance is being deleted. This field is read-only. /// - internal static readonly EventId DeletingInstance = new EventId(++Id, nameof(DeletingInstance)); + internal static readonly EventId DeletingInstance = new(++Id, nameof(DeletingInstance)); /// /// The for when deleting a SQL LocalDB instance fails. This field is read-only. /// - internal static readonly EventId DeletingInstanceFailed = new EventId(++Id, nameof(DeletingInstanceFailed)); + internal static readonly EventId DeletingInstanceFailed = new(++Id, nameof(DeletingInstanceFailed)); /// /// The for when deleting a SQL LocalDB instance fails because it cannot be found. This field is read-only. /// - internal static readonly EventId DeletingInstanceFailedAsCannotBeNotFound = new EventId(++Id, nameof(DeletingInstanceFailedAsCannotBeNotFound)); + internal static readonly EventId DeletingInstanceFailedAsCannotBeNotFound = new(++Id, nameof(DeletingInstanceFailedAsCannotBeNotFound)); /// /// The for when deleting a SQL LocalDB instance fails because it is in use. This field is read-only. /// - internal static readonly EventId DeletingInstanceFailedAsInUse = new EventId(++Id, nameof(DeletingInstanceFailedAsInUse)); + internal static readonly EventId DeletingInstanceFailedAsInUse = new(++Id, nameof(DeletingInstanceFailedAsInUse)); /// /// The for when a SQL LocalDB instance has been deleted. This field is read-only. /// - internal static readonly EventId DeletedInstance = new EventId(++Id, nameof(DeletedInstance)); + internal static readonly EventId DeletedInstance = new(++Id, nameof(DeletedInstance)); /// /// The for when the files for a SQL LocalDB instance are being deleted. This field is read-only. /// - internal static readonly EventId DeletingInstanceFiles = new EventId(++Id, nameof(DeletingInstanceFiles)); + internal static readonly EventId DeletingInstanceFiles = new(++Id, nameof(DeletingInstanceFiles)); /// /// The for when the files for a SQL LocalDB instance fail to be deleted. This field is read-only. /// - internal static readonly EventId DeletingInstanceFilesFailed = new EventId(++Id, nameof(DeletingInstanceFilesFailed)); + internal static readonly EventId DeletingInstanceFilesFailed = new(++Id, nameof(DeletingInstanceFilesFailed)); /// /// The for when the files for a SQL LocalDB instance have been deleted. This field is read-only. /// - internal static readonly EventId DeletedInstanceFiles = new EventId(++Id, nameof(DeletedInstanceFiles)); + internal static readonly EventId DeletedInstanceFiles = new(++Id, nameof(DeletedInstanceFiles)); /// /// The for when getting information about a SQL LocalDB instance. This field is read-only. /// - internal static readonly EventId GettingInstanceInfo = new EventId(++Id, nameof(GettingInstanceInfo)); + internal static readonly EventId GettingInstanceInfo = new(++Id, nameof(GettingInstanceInfo)); /// /// The for when getting information about a SQL LocalDB instance fails. This field is read-only. /// - internal static readonly EventId GettingInstanceInfoFailed = new EventId(++Id, nameof(GettingInstanceInfoFailed)); + internal static readonly EventId GettingInstanceInfoFailed = new(++Id, nameof(GettingInstanceInfoFailed)); /// /// The for when information about a SQL LocalDB instance was retrieved. This field is read-only. /// - internal static readonly EventId GotInstanceInfo = new EventId(++Id, nameof(GotInstanceInfo)); + internal static readonly EventId GotInstanceInfo = new(++Id, nameof(GotInstanceInfo)); /// /// The for when getting SQL LocalDB instance names. This field is read-only. /// - internal static readonly EventId GettingInstanceNames = new EventId(++Id, nameof(GettingInstanceNames)); + internal static readonly EventId GettingInstanceNames = new(++Id, nameof(GettingInstanceNames)); /// /// The for when getting SQL LocalDB instance names fails. This field is read-only. /// - internal static readonly EventId GettingInstanceNamesFailed = new EventId(++Id, nameof(GettingInstanceNamesFailed)); + internal static readonly EventId GettingInstanceNamesFailed = new(++Id, nameof(GettingInstanceNamesFailed)); /// /// The for when SQL LocalDB instance names are retrieved. This field is read-only. /// - internal static readonly EventId GotInstanceNames = new EventId(++Id, nameof(GotInstanceNames)); + internal static readonly EventId GotInstanceNames = new(++Id, nameof(GotInstanceNames)); /// /// The for when getting information about a SQL LocalDB version. This field is read-only. /// - internal static readonly EventId GettingVersionInfo = new EventId(++Id, nameof(GettingVersionInfo)); + internal static readonly EventId GettingVersionInfo = new(++Id, nameof(GettingVersionInfo)); /// /// The for when getting information about a SQL LocalDB version fails. This field is read-only. /// - internal static readonly EventId GettingVersionInfoFailed = new EventId(++Id, nameof(GettingVersionInfoFailed)); + internal static readonly EventId GettingVersionInfoFailed = new(++Id, nameof(GettingVersionInfoFailed)); /// /// The for when information about a SQL LocalDB version was retrieved. This field is read-only. /// - internal static readonly EventId GotVersionInfo = new EventId(++Id, nameof(GotVersionInfo)); + internal static readonly EventId GotVersionInfo = new(++Id, nameof(GotVersionInfo)); /// /// The for when getting SQL LocalDB versions. This field is read-only. /// - internal static readonly EventId GettingVersions = new EventId(++Id, nameof(GettingVersions)); + internal static readonly EventId GettingVersions = new(++Id, nameof(GettingVersions)); /// /// The for when getting SQL LocalDB versions fails. This field is read-only. /// - internal static readonly EventId GettingVersionsFailed = new EventId(++Id, nameof(GettingVersionsFailed)); + internal static readonly EventId GettingVersionsFailed = new(++Id, nameof(GettingVersionsFailed)); /// /// The for when SQL LocalDB instance versions are retrieved. This field is read-only. /// - internal static readonly EventId GotVersions = new EventId(++Id, nameof(GotVersions)); + internal static readonly EventId GotVersions = new(++Id, nameof(GotVersions)); /// /// The for when a specified Language Id is invalid. This field is read-only. /// - internal static readonly EventId InvalidLanguageId = new EventId(++Id, nameof(InvalidLanguageId)); + internal static readonly EventId InvalidLanguageId = new(++Id, nameof(InvalidLanguageId)); /// /// The for when a specified registry key name is invalid. This field is read-only. /// - internal static readonly EventId InvalidRegistryKey = new EventId(++Id, nameof(InvalidRegistryKey)); + internal static readonly EventId InvalidRegistryKey = new(++Id, nameof(InvalidRegistryKey)); /// /// The for when a registry key cannot be found. This field is read-only. /// - internal static readonly EventId RegistryKeyNotFound = new EventId(++Id, nameof(RegistryKeyNotFound)); + internal static readonly EventId RegistryKeyNotFound = new(++Id, nameof(RegistryKeyNotFound)); /// /// The for when a SQL LocalDB instance is starting. This field is read-only. /// - internal static readonly EventId StartingInstance = new EventId(++Id, nameof(StartingInstance)); + internal static readonly EventId StartingInstance = new(++Id, nameof(StartingInstance)); /// /// The for when a SQL LocalDB instance fails to start. This field is read-only. /// - internal static readonly EventId StartingInstanceFailed = new EventId(++Id, nameof(StartingInstanceFailed)); + internal static readonly EventId StartingInstanceFailed = new(++Id, nameof(StartingInstanceFailed)); /// /// The for when a SQL LocalDB instance has started. This field is read-only. /// - internal static readonly EventId StartedInstance = new EventId(++Id, nameof(StartedInstance)); + internal static readonly EventId StartedInstance = new(++Id, nameof(StartedInstance)); /// /// The for when a SQL LocalDB instance is stopping. This field is read-only. /// - internal static readonly EventId StoppingInstance = new EventId(++Id, nameof(StoppingInstance)); + internal static readonly EventId StoppingInstance = new(++Id, nameof(StoppingInstance)); /// /// The for when a SQL LocalDB instance fails to stop. This field is read-only. /// - internal static readonly EventId StoppingInstanceFailed = new EventId(++Id, nameof(StoppingInstanceFailed)); + internal static readonly EventId StoppingInstanceFailed = new(++Id, nameof(StoppingInstanceFailed)); /// /// The for when a SQL LocalDB instance has stopped. This field is read-only. /// - internal static readonly EventId StoppedInstance = new EventId(++Id, nameof(StoppedInstance)); + internal static readonly EventId StoppedInstance = new(++Id, nameof(StoppedInstance)); /// /// The for when SQL LocalDB API tracing is starting. This field is read-only. /// - internal static readonly EventId StartingTracing = new EventId(++Id, nameof(StartingTracing)); + internal static readonly EventId StartingTracing = new(++Id, nameof(StartingTracing)); /// /// The for when tracing for SQL LocalDB API fails to start. This field is read-only. /// - internal static readonly EventId StartingTracingFailed = new EventId(++Id, nameof(StartingTracingFailed)); + internal static readonly EventId StartingTracingFailed = new(++Id, nameof(StartingTracingFailed)); /// /// The for when SQL LocalDB API tracing is started. This field is read-only. /// - internal static readonly EventId StartedTracing = new EventId(++Id, nameof(StartedTracing)); + internal static readonly EventId StartedTracing = new(++Id, nameof(StartedTracing)); /// /// The for when SQL LocalDB API tracing is stopping. This field is read-only. /// - internal static readonly EventId StoppedTracing = new EventId(++Id, nameof(StoppedTracing)); + internal static readonly EventId StoppedTracing = new(++Id, nameof(StoppedTracing)); /// /// The for when tracing for SQL LocalDB API fails to stop. This field is read-only. /// - internal static readonly EventId StoppingTracingFailed = new EventId(++Id, nameof(StoppingTracingFailed)); + internal static readonly EventId StoppingTracingFailed = new(++Id, nameof(StoppingTracingFailed)); /// /// The for when SQL LocalDB API tracing is stopped. This field is read-only. /// - internal static readonly EventId StoppingTracing = new EventId(++Id, nameof(StoppingTracing)); + internal static readonly EventId StoppingTracing = new(++Id, nameof(StoppingTracing)); /// /// The for when a temporary SQL LocalDB API instance fails to stop. This field is read-only. /// - internal static readonly EventId StopTemporaryInstanceFailed = new EventId(++Id, nameof(StopTemporaryInstanceFailed)); + internal static readonly EventId StopTemporaryInstanceFailed = new(++Id, nameof(StopTemporaryInstanceFailed)); /// /// The for when a SQL LocalDB instance is being shared. This field is read-only. /// - internal static readonly EventId SharingInstance = new EventId(++Id, nameof(SharingInstance)); + internal static readonly EventId SharingInstance = new(++Id, nameof(SharingInstance)); /// /// The for when sharing a SQL LocalDB instance fails. This field is read-only. /// - internal static readonly EventId SharingInstanceFailed = new EventId(++Id, nameof(SharingInstanceFailed)); + internal static readonly EventId SharingInstanceFailed = new(++Id, nameof(SharingInstanceFailed)); /// /// The for when a SQL LocalDB instance has been shared. This field is read-only. /// - internal static readonly EventId SharedInstance = new EventId(++Id, nameof(SharedInstance)); + internal static readonly EventId SharedInstance = new(++Id, nameof(SharedInstance)); /// /// The for when a SQL LocalDB instance is being unshared. This field is read-only. /// - internal static readonly EventId UnsharingInstance = new EventId(++Id, nameof(UnsharingInstance)); + internal static readonly EventId UnsharingInstance = new(++Id, nameof(UnsharingInstance)); /// /// The for when unsharing a SQL LocalDB instance fails. This field is read-only. /// - internal static readonly EventId UnsharingInstanceFailed = new EventId(++Id, nameof(UnsharingInstanceFailed)); + internal static readonly EventId UnsharingInstanceFailed = new(++Id, nameof(UnsharingInstanceFailed)); /// /// The for when a SQL LocalDB instance has been unshared. This field is read-only. /// - internal static readonly EventId UnsharedInstance = new EventId(++Id, nameof(UnsharedInstance)); + internal static readonly EventId UnsharedInstance = new(++Id, nameof(UnsharedInstance)); /// /// The for when the SQL LocalDB Instance API is unloaded. This field is read-only. /// - internal static readonly EventId NativeApiUnloaded = new EventId(++Id, nameof(NativeApiUnloaded)); + internal static readonly EventId NativeApiUnloaded = new(++Id, nameof(NativeApiUnloaded)); /// /// The for when the SQL LocalDB Instance API returns a generic error. This field is read-only. /// - internal static readonly EventId GenericError = new EventId(++Id, nameof(GenericError)); + internal static readonly EventId GenericError = new(++Id, nameof(GenericError)); /// /// The base Id for the event Ids. diff --git a/src/SqlLocalDb/Interop/LocalDbInstanceApi.cs b/src/SqlLocalDb/Interop/LocalDbInstanceApi.cs index 2610923b..12a6c7d8 100644 --- a/src/SqlLocalDb/Interop/LocalDbInstanceApi.cs +++ b/src/SqlLocalDb/Interop/LocalDbInstanceApi.cs @@ -41,12 +41,12 @@ internal sealed class LocalDbInstanceApi : IDisposable /// /// An array containing the null character. This field is read-only. /// - private static readonly char[] _nullArray = new char[] { '\0' }; + private static readonly char[] _nullArray = new[] { '\0' }; /// /// Synchronization object to protect loading the native library and its functions. This field is read-only. /// - private readonly object _syncRoot = new object(); + private readonly object _syncRoot = new(); /// /// Whether the instance has been disposed of. diff --git a/src/SqlLocalDb/Interop/LocalDbInstanceInfo.cs b/src/SqlLocalDb/Interop/LocalDbInstanceInfo.cs index affa0371..cd49d260 100644 --- a/src/SqlLocalDb/Interop/LocalDbInstanceInfo.cs +++ b/src/SqlLocalDb/Interop/LocalDbInstanceInfo.cs @@ -199,7 +199,7 @@ DateTime ISqlLocalDbInstanceInfo.LastStartTimeUtc /// /// Gets the LocalDB version for the instance. /// - Version ISqlLocalDbInstanceInfo.LocalDbVersion => new Version((int)Major, (int)Minor, (int)Build, (int)Revision); + Version ISqlLocalDbInstanceInfo.LocalDbVersion => new((int)Major, (int)Minor, (int)Build, (int)Revision); /// /// Gets the name of the instance. diff --git a/src/SqlLocalDb/Interop/LocalDbVersionInfo.cs b/src/SqlLocalDb/Interop/LocalDbVersionInfo.cs index 904c6295..ff2643fb 100644 --- a/src/SqlLocalDb/Interop/LocalDbVersionInfo.cs +++ b/src/SqlLocalDb/Interop/LocalDbVersionInfo.cs @@ -91,7 +91,7 @@ internal struct LocalDbVersionInfo : ISqlLocalDbVersionInfo /// /// Gets the version. /// - Version ISqlLocalDbVersionInfo.Version => new Version((int)Major, (int)Minor, (int)Build, (int)Revision); + Version ISqlLocalDbVersionInfo.Version => new((int)Major, (int)Minor, (int)Build, (int)Revision); /// /// Gets the name to display in the debugger. diff --git a/src/SqlLocalDb/SqlLocalDbApi.cs b/src/SqlLocalDb/SqlLocalDbApi.cs index 885fd2d3..bd5865e0 100644 --- a/src/SqlLocalDb/SqlLocalDbApi.cs +++ b/src/SqlLocalDb/SqlLocalDbApi.cs @@ -1270,7 +1270,7 @@ internal Exception GetLocalDbError(int hr, EventId eventId, string instanceName private static byte[] GetOwnerSidAsByteArray(string ownerSid) { // Get the binary version of the SID from its string - SecurityIdentifier sid = new SecurityIdentifier(ownerSid); + SecurityIdentifier sid = new(ownerSid); byte[] binaryForm = new byte[SecurityIdentifier.MaxBinaryLength]; sid.GetBinaryForm(binaryForm, 0); return binaryForm; @@ -1296,7 +1296,7 @@ private static string[] MarshalStringArray(IntPtr ptr, int length, int count) for (int i = 0; i < result.Length; i++) { // Determine the offset of the element, and get the string from the array - IntPtr offset = new IntPtr(ptr.ToInt64() + (length * i)); + IntPtr offset = new(ptr.ToInt64() + (length * i)); result[i] = Marshal.PtrToStringAuto(offset)!; } diff --git a/src/TestApp/Program.cs b/src/TestApp/Program.cs index 350711a2..95dc13b4 100644 --- a/src/TestApp/Program.cs +++ b/src/TestApp/Program.cs @@ -131,7 +131,7 @@ internal static async Task Main(string[] args) private static async Task ExecuteCommandAsync(SqlConnection connection, Action configure) { - using SqlCommand command = new SqlCommand() + using SqlCommand command = new() { Connection = connection, }; @@ -156,8 +156,8 @@ private static bool IsCurrentUserAdmin() } using WindowsIdentity identity = WindowsIdentity.GetCurrent(); + WindowsPrincipal principal = new(identity); - WindowsPrincipal principal = new WindowsPrincipal(identity); return principal.IsInRole(WindowsBuiltInRole.Administrator); } diff --git a/tests/SqlLocalDb.Tests/DelayedMessageBus.cs b/tests/SqlLocalDb.Tests/DelayedMessageBus.cs index b1cd0c3f..d7c6e3af 100644 --- a/tests/SqlLocalDb.Tests/DelayedMessageBus.cs +++ b/tests/SqlLocalDb.Tests/DelayedMessageBus.cs @@ -8,7 +8,7 @@ namespace MartinCostello.SqlLocalDb; internal sealed class DelayedMessageBus : IMessageBus { private readonly IMessageBus _inner; - private readonly List _messages = new List(); + private readonly List _messages = new(); internal DelayedMessageBus(IMessageBus inner) { diff --git a/tests/SqlLocalDb.Tests/Examples.cs b/tests/SqlLocalDb.Tests/Examples.cs index 0ea197f2..1a000263 100644 --- a/tests/SqlLocalDb.Tests/Examples.cs +++ b/tests/SqlLocalDb.Tests/Examples.cs @@ -22,42 +22,36 @@ public Examples(ITestOutputHelper outputHelper) [WindowsOnlyFact] public async Task Create_A_Sql_LocalDB_Instance() { - using (var localDB = new SqlLocalDbApi(OutputHelper.ToLoggerFactory())) - { - ISqlLocalDbInstanceInfo instance = localDB.GetOrCreateInstance("MyInstance"); - ISqlLocalDbInstanceManager manager = instance.Manage(); + using var localDB = new SqlLocalDbApi(OutputHelper.ToLoggerFactory()); - if (!instance.IsRunning) - { - manager.Start(); - } + ISqlLocalDbInstanceInfo instance = localDB.GetOrCreateInstance("MyInstance"); + ISqlLocalDbInstanceManager manager = instance.Manage(); - await using (SqlConnection connection = instance.CreateConnection()) - { - connection.Open(); + if (!instance.IsRunning) + { + manager.Start(); + } - // Use the SQL connection... - } + await using (SqlConnection connection = instance.CreateConnection()) + { + connection.Open(); - manager.Stop(); + // Use the SQL connection... } + + manager.Stop(); } [WindowsOnlyFact] public async Task Create_A_Temporary_Sql_LocalDB_Instance() { - using (var localDB = new SqlLocalDbApi(OutputHelper.ToLoggerFactory())) - { - using (TemporarySqlLocalDbInstance instance = localDB.CreateTemporaryInstance(deleteFiles: true)) - { - await using (var connection = new SqlConnection(instance.ConnectionString)) - { - connection.Open(); - - // Use the SQL connection... - } - } - } + using var localDB = new SqlLocalDbApi(OutputHelper.ToLoggerFactory()); + using TemporarySqlLocalDbInstance instance = localDB.CreateTemporaryInstance(deleteFiles: true); + + await using var connection = new SqlConnection(instance.ConnectionString); + connection.Open(); + + // Use the SQL connection... } [WindowsOnlyFact] @@ -70,23 +64,20 @@ public async Task Use_With_Dependency_Injection() IServiceProvider serviceProvider = services.BuildServiceProvider(); - await using (AsyncServiceScope scope = serviceProvider.CreateAsyncScope()) - { - ISqlLocalDbApi localDB = scope!.ServiceProvider!.GetRequiredService(); - ISqlLocalDbInstanceInfo instance = localDB!.GetDefaultInstance(); - ISqlLocalDbInstanceManager manager = instance.Manage(); - - if (!instance.IsRunning) - { - manager.Start(); - } + await using AsyncServiceScope scope = serviceProvider.CreateAsyncScope(); - await using (SqlConnection connection = instance.CreateConnection()) - { - connection.Open(); + ISqlLocalDbApi localDB = scope!.ServiceProvider!.GetRequiredService(); + ISqlLocalDbInstanceInfo instance = localDB!.GetDefaultInstance(); + ISqlLocalDbInstanceManager manager = instance.Manage(); - // Use the SQL connection... - } + if (!instance.IsRunning) + { + manager.Start(); } + + await using SqlConnection connection = instance.CreateConnection(); + connection.Open(); + + // Use the SQL connection... } } diff --git a/tests/SqlLocalDb.Tests/NotInParallelTests.cs b/tests/SqlLocalDb.Tests/NotInParallelTests.cs index dcdd6263..9e7a78b0 100644 --- a/tests/SqlLocalDb.Tests/NotInParallelTests.cs +++ b/tests/SqlLocalDb.Tests/NotInParallelTests.cs @@ -22,30 +22,29 @@ public NotInParallelTests(ITestOutputHelper outputHelper) public void Can_Delete_User_Instances() { // Arrange - using (var actual = new SqlLocalDbApi(_loggerFactory)) - { - actual.CreateInstance(Guid.NewGuid().ToString()); + using var actual = new SqlLocalDbApi(_loggerFactory); + actual.CreateInstance(Guid.NewGuid().ToString()); + + IReadOnlyList namesBefore = actual.GetInstanceNames(); - IReadOnlyList namesBefore = actual.GetInstanceNames(); + // Act + int deleted = actual.DeleteUserInstances(deleteFiles: true); - // Act - int deleted = actual.DeleteUserInstances(deleteFiles: true); + // Assert + deleted.ShouldBeGreaterThanOrEqualTo(1); - // Assert - deleted.ShouldBeGreaterThanOrEqualTo(1); - IReadOnlyList namesAfter = actual.GetInstanceNames(); + IReadOnlyList namesAfter = actual.GetInstanceNames(); - int instancesDeleted = 0; + int instancesDeleted = 0; - foreach (string name in namesBefore) + foreach (string name in namesBefore) + { + if (!namesAfter.Contains(name)) { - if (!namesAfter.Contains(name)) - { - instancesDeleted++; - } + instancesDeleted++; } - - instancesDeleted.ShouldBeGreaterThanOrEqualTo(1); } + + instancesDeleted.ShouldBeGreaterThanOrEqualTo(1); } } diff --git a/tests/SqlLocalDb.Tests/RunAsAdminFactAttribute.cs b/tests/SqlLocalDb.Tests/RunAsAdminFactAttribute.cs index 5a620f0a..3e0b58de 100644 --- a/tests/SqlLocalDb.Tests/RunAsAdminFactAttribute.cs +++ b/tests/SqlLocalDb.Tests/RunAsAdminFactAttribute.cs @@ -51,10 +51,9 @@ private static bool IsCurrentUserAdmin(out string name) return false; } - using (var identity = WindowsIdentity.GetCurrent()) - { - name = identity.Name; - return new WindowsPrincipal(identity).IsInRole(WindowsBuiltInRole.Administrator); - } + using var identity = WindowsIdentity.GetCurrent(); + name = identity.Name; + + return new WindowsPrincipal(identity).IsInRole(WindowsBuiltInRole.Administrator); } } diff --git a/tests/SqlLocalDb.Tests/SqlLocalDbApiTests.cs b/tests/SqlLocalDb.Tests/SqlLocalDbApiTests.cs index dd46951d..f6b9c08d 100644 --- a/tests/SqlLocalDb.Tests/SqlLocalDbApiTests.cs +++ b/tests/SqlLocalDb.Tests/SqlLocalDbApiTests.cs @@ -379,7 +379,7 @@ public void SqlLocalDbApi_Is_ISqlLocalDbApiAdapter() public void SqlLocalDbApi_Throws_Exception_For_Native_Errors() { // Arrange - string instanceName = new string('$', 10000); + string instanceName = new('$', 10000); using var actual = new SqlLocalDbApi(_loggerFactory); From d5bdf89f813f92f768b38b4f9b351d9baba74b2b Mon Sep 17 00:00:00 2001 From: martincostello Date: Sun, 22 Aug 2021 10:30:44 +0100 Subject: [PATCH 18/29] Use top-level program Use a top-level program instead of having an explicit Program and Main. --- src/TestApp/Program.cs | 297 +++++++++++++++++++---------------------- 1 file changed, 138 insertions(+), 159 deletions(-) diff --git a/src/TestApp/Program.cs b/src/TestApp/Program.cs index 95dc13b4..7b70725d 100644 --- a/src/TestApp/Program.cs +++ b/src/TestApp/Program.cs @@ -4,186 +4,165 @@ using System.Reflection; using System.Runtime.InteropServices; using System.Security.Principal; +using MartinCostello.SqlLocalDb; using Microsoft.Data.SqlClient; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -namespace MartinCostello.SqlLocalDb; +PrintBanner(); -/// -/// An application that acts as a test harness for the MartinCostello.SqlLocalDb assembly. This class cannot be inherited. -/// -internal static class Program +var options = new SqlLocalDbOptions() { - /// - /// The main entry point to the application. - /// - /// The command-line arguments passed to the application. - /// - /// A representing the asynchronous application. - /// - internal static async Task Main(string[] args) - { - PrintBanner(); + AutomaticallyDeleteInstanceFiles = true, + StopOptions = StopInstanceOptions.NoWait, +}; - var options = new SqlLocalDbOptions() - { - AutomaticallyDeleteInstanceFiles = true, - StopOptions = StopInstanceOptions.NoWait, - }; +var services = new ServiceCollection() + .AddLogging((p) => p.AddConsole().SetMinimumLevel(LogLevel.Debug)); - var services = new ServiceCollection().AddLogging((p) => p.AddConsole().SetMinimumLevel(LogLevel.Debug)); - var loggerFactory = services.BuildServiceProvider().GetRequiredService(); +using var serviceProvider = services.BuildServiceProvider(); - using (var localDB = new SqlLocalDbApi(options, loggerFactory)) - { - if (!localDB.IsLocalDBInstalled()) - { - Console.WriteLine(SR.SqlLocalDbApi_NotInstalledFormat, Environment.MachineName); - return; - } - - if (args?.Length == 1 && - (string.Equals(args[0], "/deleteuserinstances", StringComparison.OrdinalIgnoreCase) || - string.Equals(args[0], "--delete-user-instances", StringComparison.OrdinalIgnoreCase))) - { - localDB.DeleteUserInstances(deleteFiles: true); - } - - IReadOnlyList versions = localDB.GetVersions(); - - Console.WriteLine(Strings.Program_VersionsListHeader); - Console.WriteLine(); - - foreach (ISqlLocalDbVersionInfo version in versions) - { - Console.WriteLine(version.Name); - } - - Console.WriteLine(); - - IReadOnlyList instances = localDB.GetInstances(); - - Console.WriteLine(Strings.Program_InstancesListHeader); - Console.WriteLine(); - - foreach (ISqlLocalDbInstanceInfo instanceInfo in instances) - { - Console.WriteLine(instanceInfo.Name); - } - - Console.WriteLine(); - - string instanceName = Guid.NewGuid().ToString(); - - ISqlLocalDbInstanceInfo instance = localDB.CreateInstance(instanceName); - - var manager = new SqlLocalDbInstanceManager(instance, localDB); - manager.Start(); - - try - { - if (IsCurrentUserAdmin()) - { - manager.Share(Guid.NewGuid().ToString()); - } - - try - { - using SqlConnection connection = manager.CreateConnection(); - await connection.OpenAsync(); - - try - { - await ExecuteCommandAsync(connection, (command) => command.CommandText = "create database [MyDatabase]"); - await ExecuteCommandAsync(connection, (command) => command.CommandText = "drop database [MyDatabase]"); - } - finally - { - await connection.CloseAsync(); - } - } - finally - { - if (IsCurrentUserAdmin()) - { - manager.Unshare(); - } - } - } -#pragma warning disable CA1031 - catch (Exception ex) - { - Console.WriteLine(ex.ToString()); - } -#pragma warning restore CA1031 - finally - { - manager.Stop(); - localDB.DeleteInstance(instance.Name); - } - } +var loggerFactory = serviceProvider.GetRequiredService(); - Console.WriteLine(); - Console.Write(Strings.Program_ExitPrompt); - Console.ReadKey(); - } +using var localDB = new SqlLocalDbApi(options, loggerFactory); - private static async Task ExecuteCommandAsync(SqlConnection connection, Action configure) - { - using SqlCommand command = new() - { - Connection = connection, - }; +if (!localDB.IsLocalDBInstalled()) +{ + Console.WriteLine(SR.SqlLocalDbApi_NotInstalledFormat, Environment.MachineName); + return; +} + +if (args?.Length == 1 && + (string.Equals(args[0], "/deleteuserinstances", StringComparison.OrdinalIgnoreCase) || + string.Equals(args[0], "--delete-user-instances", StringComparison.OrdinalIgnoreCase))) +{ + localDB.DeleteUserInstances(deleteFiles: true); +} + +IReadOnlyList versions = localDB.GetVersions(); + +Console.WriteLine(Strings.Program_VersionsListHeader); + +Console.WriteLine(); + +foreach (ISqlLocalDbVersionInfo version in versions) +{ + Console.WriteLine(version.Name); +} + +Console.WriteLine(); + +IReadOnlyList instances = localDB.GetInstances(); + +Console.WriteLine(Strings.Program_InstancesListHeader); + +Console.WriteLine(); + +foreach (ISqlLocalDbInstanceInfo instanceInfo in instances) +{ + Console.WriteLine(instanceInfo.Name); +} + +Console.WriteLine(); + +string instanceName = Guid.NewGuid().ToString(); + +ISqlLocalDbInstanceInfo instance = localDB.CreateInstance(instanceName); + +var manager = new SqlLocalDbInstanceManager(instance, localDB); - configure(command); +manager.Start(); - await command.ExecuteNonQueryAsync(); +try +{ + if (IsCurrentUserAdmin()) + { + manager.Share(Guid.NewGuid().ToString()); } - /// - /// Returns whether the current user is in the administrators group on the local machine. - /// - /// - /// if the current user is in the administrators - /// group on the local machine; otherwise . - /// - private static bool IsCurrentUserAdmin() + try { - if (!OperatingSystem.IsWindows()) + using SqlConnection connection = manager.CreateConnection(); + await connection.OpenAsync(); + + try + { + await ExecuteCommandAsync(connection, (command) => command.CommandText = "create database [MyDatabase]"); + await ExecuteCommandAsync(connection, (command) => command.CommandText = "drop database [MyDatabase]"); + } + finally { - return false; + await connection.CloseAsync(); } + } + finally + { + if (IsCurrentUserAdmin()) + { + manager.Unshare(); + } + } +} +catch (Exception ex) +{ + Console.WriteLine(ex.ToString()); +} +finally +{ + manager.Stop(); + localDB.DeleteInstance(instance.Name); +} - using WindowsIdentity identity = WindowsIdentity.GetCurrent(); - WindowsPrincipal principal = new(identity); +Console.WriteLine(); - return principal.IsInRole(WindowsBuiltInRole.Administrator); - } +Console.Write(Strings.Program_ExitPrompt); + +Console.ReadKey(); + +static async Task ExecuteCommandAsync(SqlConnection connection, Action configure) +{ + using SqlCommand command = new() + { + Connection = connection, + }; + + configure(command); + + await command.ExecuteNonQueryAsync(); +} - /// - /// Prints a banner to the console containing assembly and operating system information. - /// - private static void PrintBanner() +static bool IsCurrentUserAdmin() +{ + if (!OperatingSystem.IsWindows()) { - Assembly assembly = typeof(SqlLocalDbApi).Assembly; - AssemblyName assemblyName = assembly.GetName(); - - Console.WriteLine( - Strings.Program_BannerFormat, - assemblyName.Name, - assembly.GetCustomAttribute()?.Copyright, - assemblyName.Version, - assembly.GetCustomAttribute()?.Version, - assembly.GetCustomAttribute()?.InformationalVersion, - assembly.GetCustomAttribute()?.Configuration, - Environment.UserDomainName, - Environment.UserName, - IsCurrentUserAdmin(), - Environment.OSVersion, - RuntimeInformation.OSDescription, - RuntimeInformation.FrameworkDescription, - RuntimeInformation.OSArchitecture, - RuntimeInformation.ProcessArchitecture); + return false; } + + using WindowsIdentity identity = WindowsIdentity.GetCurrent(); + WindowsPrincipal principal = new(identity); + + return principal.IsInRole(WindowsBuiltInRole.Administrator); +} + +static void PrintBanner() +{ + Assembly assembly = typeof(SqlLocalDbApi).Assembly; + AssemblyName assemblyName = assembly.GetName(); + + Console.WriteLine( + Strings.Program_BannerFormat, + assemblyName.Name, + assembly.GetCustomAttribute()?.Copyright, + assemblyName.Version, + assembly.GetCustomAttribute()?.Version, + assembly.GetCustomAttribute()?.InformationalVersion, + assembly.GetCustomAttribute()?.Configuration, + Environment.UserDomainName, + Environment.UserName, + IsCurrentUserAdmin(), + Environment.OSVersion, + RuntimeInformation.OSDescription, + RuntimeInformation.FrameworkDescription, + RuntimeInformation.OSArchitecture, + RuntimeInformation.ProcessArchitecture); } From e4d61eef3fc5373b6cd2c193cbd33a0e953a739b Mon Sep 17 00:00:00 2001 From: martincostello Date: Sun, 22 Aug 2021 11:01:44 +0100 Subject: [PATCH 19/29] Use minimal hosting Switch to minimal hosting for the sample app. --- samples/TodoApp/Program.cs | 60 ++++++++++++++++++++++---- samples/TodoApp/Startup.cs | 79 ---------------------------------- samples/TodoApp/TodoApp.csproj | 2 +- 3 files changed, 53 insertions(+), 88 deletions(-) delete mode 100644 samples/TodoApp/Startup.cs diff --git a/samples/TodoApp/Program.cs b/samples/TodoApp/Program.cs index 06758e1c..7fcd2e69 100644 --- a/samples/TodoApp/Program.cs +++ b/samples/TodoApp/Program.cs @@ -1,17 +1,61 @@ // Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -namespace TodoApp; +using MartinCostello.SqlLocalDb; +using Microsoft.EntityFrameworkCore; +using NodaTime; +using TodoApp.Data; +using TodoApp.Services; -public static class Program +var builder = WebApplication.CreateBuilder(args); + +builder.Services.AddSqlLocalDB(); + +builder.Services.AddSingleton((_) => SystemClock.Instance); +builder.Services.AddScoped(); +builder.Services.AddScoped(); + +builder.Services.AddControllersWithViews(); + +builder.Services.AddDbContext((serviceProvider, options) => { - public static void Main(string[] args) + // Check that SQL Server LocalDB is installed + ISqlLocalDbApi localDB = serviceProvider.GetRequiredService(); + + if (!localDB.IsLocalDBInstalled()) { - CreateWebHostBuilder(args).Build().Run(); + throw new NotSupportedException("SQL LocalDB is not installed."); } - public static IHostBuilder CreateWebHostBuilder(string[] args) => - Host.CreateDefaultBuilder(args) - .ConfigureWebHostDefaults( - (webHostBuilder) => webHostBuilder.UseStartup()); + // Get the configured SQL LocalDB instance to store the TODO items in, creating it if it does not exist + IConfiguration config = serviceProvider.GetRequiredService(); + ISqlLocalDbInstanceInfo instance = localDB.GetOrCreateInstance(config["SqlLocalDbInstance"]); + + // Ensure that the SQL LocalDB instance is running and start it if not already running + if (!instance.IsRunning) + { + instance.Manage().Start(); + } + + // Get the SQL connection string to use to connect to the LocalDB instance + string connectionString = instance.GetConnectionString(); + options.UseSqlServer(connectionString); +}); + +var app = builder.Build(); + +if (!app.Environment.IsDevelopment()) +{ + app.UseExceptionHandler("/Home/Error"); + app.UseHsts(); + app.UseHttpsRedirection(); } + +app.UseStaticFiles(); +app.UseRouting(); +app.MapDefaultControllerRoute(); + +// Ensure that the database and schema exists +TodoInitializer.Initialize(app.Services); + +app.Run(); diff --git a/samples/TodoApp/Startup.cs b/samples/TodoApp/Startup.cs deleted file mode 100644 index 2ba1b655..00000000 --- a/samples/TodoApp/Startup.cs +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright (c) Martin Costello, 2012-2018. All rights reserved. -// Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. - -using MartinCostello.SqlLocalDb; -using Microsoft.EntityFrameworkCore; -using NodaTime; -using TodoApp.Data; -using TodoApp.Services; - -namespace TodoApp; - -public class Startup -{ - public Startup(IConfiguration configuration) - { - Configuration = configuration; - } - - public IConfiguration Configuration { get; } - - public void ConfigureServices(IServiceCollection services) - { - services.AddSqlLocalDB(); - - services.AddSingleton((_) => SystemClock.Instance); - services.AddScoped(); - services.AddScoped(); - - services.AddControllersWithViews(); - - services.AddDbContext(AddTodoContext); - } - - public void Configure(IApplicationBuilder app, IWebHostEnvironment env) - { - if (env.IsDevelopment()) - { - app.UseDeveloperExceptionPage(); - } - else - { - app.UseExceptionHandler("/Home/Error"); - app.UseHsts(); - } - - app.UseHttpsRedirection(); - app.UseStaticFiles(); - app.UseRouting(); - app.UseEndpoints((endpoints) => endpoints.MapDefaultControllerRoute()); - - // Ensure that the database and schema exists - TodoInitializer.Initialize(app.ApplicationServices); - } - - private static void AddTodoContext(IServiceProvider serviceProvider, DbContextOptionsBuilder options) - { - // Check that SQL Server LocalDB is installed - ISqlLocalDbApi localDB = serviceProvider.GetRequiredService(); - - if (!localDB.IsLocalDBInstalled()) - { - throw new NotSupportedException("SQL LocalDB is not installed."); - } - - // Get the configured SQL LocalDB instance to store the TODO items in, creating it if it does not exist - IConfiguration config = serviceProvider.GetRequiredService(); - ISqlLocalDbInstanceInfo instance = localDB.GetOrCreateInstance(config["SqlLocalDbInstance"]); - - // Ensure that the SQL LocalDB instance is running and start it if not already running - if (!instance.IsRunning) - { - instance.Manage().Start(); - } - - // Get the SQL connection string to use to connect to the LocalDB instance - string connectionString = instance.GetConnectionString(); - options.UseSqlServer(connectionString); - } -} diff --git a/samples/TodoApp/TodoApp.csproj b/samples/TodoApp/TodoApp.csproj index 1c4f0180..8ab85f17 100644 --- a/samples/TodoApp/TodoApp.csproj +++ b/samples/TodoApp/TodoApp.csproj @@ -2,7 +2,7 @@ inprocess false - $(NoWarn);CA1062;CA1303;CA1822;CA2007;CA2227;SA1600 + $(NoWarn);CA1062;CA1303;CA1822;CA2007;CA2227;SA1516;SA1600 TodoApp net6.0 From cc42de922842ab28dcfac15cdd1130dcc61b3f9b Mon Sep 17 00:00:00 2001 From: martincostello Date: Sun, 5 Sep 2021 14:13:15 +0100 Subject: [PATCH 20/29] Update .NET SDK Update to the latest .NET 6 RC1 SDK. --- Directory.Packages.props | 12 ++++++------ global.json | 2 +- .../ISqlLocalDbApiExtensionsTests.cs | 9 ++------- .../MartinCostello.SqlLocalDb.Tests.csproj | 1 + 4 files changed, 10 insertions(+), 14 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 67fececa..60d72795 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -8,7 +8,7 @@ - + @@ -29,14 +29,14 @@ - - + + - - - + + + diff --git a/global.json b/global.json index a46c8f7e..0131c744 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "6.0.100-rc.1.21420.39", + "version": "6.0.100-rc.1.21453.49", "allowPrerelease": false, "rollForward": "latestMajor" } diff --git a/tests/SqlLocalDb.Tests/ISqlLocalDbApiExtensionsTests.cs b/tests/SqlLocalDb.Tests/ISqlLocalDbApiExtensionsTests.cs index 0728146b..465435ab 100644 --- a/tests/SqlLocalDb.Tests/ISqlLocalDbApiExtensionsTests.cs +++ b/tests/SqlLocalDb.Tests/ISqlLocalDbApiExtensionsTests.cs @@ -15,18 +15,13 @@ public ISqlLocalDbApiExtensionsTests(ITestOutputHelper outputHelper) _loggerFactory = outputHelper.ToLoggerFactory(); } - [Theory] + [SkippableTheory] [InlineData(unchecked((int)0x89c50112))] [InlineData(unchecked((int)0x89c50108))] public static void TemporaryInstance_Ignores_Exception_If_Delete_Fails(int errorCode) { // Arrange - if (!SqlLocalDbApi.IsWindows) - { - // HACK Theories dont seem to work correctly with subclasses now - // so cannot make a derived class for a "Windows-only" theory. - return; - } + Skip.IfNot(SqlLocalDbApi.IsWindows); // Arrange var mock = new Mock(); diff --git a/tests/SqlLocalDb.Tests/MartinCostello.SqlLocalDb.Tests.csproj b/tests/SqlLocalDb.Tests/MartinCostello.SqlLocalDb.Tests.csproj index fe9515a6..1a1d4acf 100644 --- a/tests/SqlLocalDb.Tests/MartinCostello.SqlLocalDb.Tests.csproj +++ b/tests/SqlLocalDb.Tests/MartinCostello.SqlLocalDb.Tests.csproj @@ -25,6 +25,7 @@ + From 5a102ba7ec99e63bb82ae1be6208a0fa1c41bf2e Mon Sep 17 00:00:00 2001 From: martincostello Date: Tue, 14 Sep 2021 22:38:41 +0100 Subject: [PATCH 21/29] Update to .NET 6 release candidate 1 Update to release candidate 1 of .NET 6. --- NuGet.config | 1 - global.json | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/NuGet.config b/NuGet.config index 31d18de7..21cb6efa 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,7 +1,6 @@ - diff --git a/global.json b/global.json index 0131c744..694c2a36 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "6.0.100-rc.1.21453.49", + "version": "6.0.100-rc.1.21458.32", "allowPrerelease": false, "rollForward": "latestMajor" } From 95fabae3b8e3929bede20b69fa86571fdbcc6155 Mon Sep 17 00:00:00 2001 From: martincostello Date: Wed, 22 Sep 2021 07:53:53 +0100 Subject: [PATCH 22/29] Update .NET SDK Update to the latest .NET 6 RC1 SDK. --- global.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global.json b/global.json index 694c2a36..e81fe228 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "6.0.100-rc.1.21458.32", + "version": "6.0.100-rc.1.21463.6", "allowPrerelease": false, "rollForward": "latestMajor" } From bc8f809beedf6789019b45dd29f9682308c465a6 Mon Sep 17 00:00:00 2001 From: martincostello Date: Wed, 22 Sep 2021 07:55:57 +0100 Subject: [PATCH 23/29] Use Microsoft.DotNet.Compatibility Update package to use Microsoft.DotNet.Compatibility. --- Directory.Packages.props | 2 +- src/SqlLocalDb/MartinCostello.SqlLocalDb.csproj | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 60d72795..b23a7ef4 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -7,7 +7,7 @@ - + diff --git a/src/SqlLocalDb/MartinCostello.SqlLocalDb.csproj b/src/SqlLocalDb/MartinCostello.SqlLocalDb.csproj index 00f087d6..fc571c7b 100644 --- a/src/SqlLocalDb/MartinCostello.SqlLocalDb.csproj +++ b/src/SqlLocalDb/MartinCostello.SqlLocalDb.csproj @@ -1,9 +1,10 @@ - SQL LocalDB Wrapper A .NET assembly providing interop with the SQL LocalDB native API from managed code using .NET APIs. + true true + true $(NoWarn);CA2235;CA2254 Library MartinCostello.SqlLocalDb @@ -19,6 +20,7 @@ + From f4b22a250a1b0e1be6ce005e5ed8825ec4811655 Mon Sep 17 00:00:00 2001 From: martincostello Date: Thu, 23 Sep 2021 07:49:38 +0100 Subject: [PATCH 24/29] Simplify package validation The analyzer is built into the .NET 6 SDK, and IsPackable doesn't need to be explicitly set. --- Directory.Packages.props | 1 - src/SqlLocalDb/MartinCostello.SqlLocalDb.csproj | 2 -- 2 files changed, 3 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index b23a7ef4..9f12dd98 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -7,7 +7,6 @@ - diff --git a/src/SqlLocalDb/MartinCostello.SqlLocalDb.csproj b/src/SqlLocalDb/MartinCostello.SqlLocalDb.csproj index fc571c7b..db0f0139 100644 --- a/src/SqlLocalDb/MartinCostello.SqlLocalDb.csproj +++ b/src/SqlLocalDb/MartinCostello.SqlLocalDb.csproj @@ -4,7 +4,6 @@ A .NET assembly providing interop with the SQL LocalDB native API from managed code using .NET APIs. true true - true $(NoWarn);CA2235;CA2254 Library MartinCostello.SqlLocalDb @@ -20,7 +19,6 @@ - From 54ad7b1de073c2ace37e64dc4aa2ff937ec259eb Mon Sep 17 00:00:00 2001 From: martincostello Date: Sat, 9 Oct 2021 15:59:24 +0100 Subject: [PATCH 25/29] Update .editorconfig Prefer file-scoped namespaces. --- .editorconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.editorconfig b/.editorconfig index 639748c6..6ff201a5 100644 --- a/.editorconfig +++ b/.editorconfig @@ -103,6 +103,9 @@ csharp_prefer_simple_default_expression = true:suggestion csharp_style_pattern_local_over_anonymous_function = true:suggestion csharp_style_inlined_variable_declaration = true:suggestion +# Namespace preferences +csharp_style_namespace_declarations = file_scoped + ############################### # C# Formatting Rules # ############################### From 1b3b0c01001fd3afdd80a66ad1431d2b7d4379b6 Mon Sep 17 00:00:00 2001 From: martincostello Date: Tue, 12 Oct 2021 22:51:53 +0100 Subject: [PATCH 26/29] Update to .NET 6 RC2 Update to release candidate 2 of .NET 6. --- Directory.Build.props | 4 ++++ Directory.Packages.props | 12 ++++++------ global.json | 2 +- samples/TodoApp/Program.cs | 2 ++ src/TestApp/Program.cs | 2 ++ tests/SqlLocalDb.Tests/Examples.cs | 6 +++--- .../ISqlLocalDbInstanceManagerExtensionsTests.cs | 2 +- 7 files changed, 19 insertions(+), 11 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 02af48cb..f9771b55 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -23,6 +23,10 @@ latest true en-US + + $(NoWarn);CA1848 $(NoWarn);CA1054;CA2234 $(NoWarn);SA0001 enable diff --git a/Directory.Packages.props b/Directory.Packages.props index 9f12dd98..bf047983 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -7,7 +7,7 @@ - + @@ -28,14 +28,14 @@ - - + + - - - + + + diff --git a/global.json b/global.json index e81fe228..bd7abc87 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "6.0.100-rc.1.21463.6", + "version": "6.0.100-rc.2.21505.57", "allowPrerelease": false, "rollForward": "latestMajor" } diff --git a/samples/TodoApp/Program.cs b/samples/TodoApp/Program.cs index 7fcd2e69..f74c9c64 100644 --- a/samples/TodoApp/Program.cs +++ b/samples/TodoApp/Program.cs @@ -1,6 +1,8 @@ // Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. +#pragma warning disable CA1812 + using MartinCostello.SqlLocalDb; using Microsoft.EntityFrameworkCore; using NodaTime; diff --git a/src/TestApp/Program.cs b/src/TestApp/Program.cs index 7b70725d..0b408533 100644 --- a/src/TestApp/Program.cs +++ b/src/TestApp/Program.cs @@ -1,6 +1,8 @@ // Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. +#pragma warning disable CA1812 + using System.Reflection; using System.Runtime.InteropServices; using System.Security.Principal; diff --git a/tests/SqlLocalDb.Tests/Examples.cs b/tests/SqlLocalDb.Tests/Examples.cs index 1a000263..f1ab0a8f 100644 --- a/tests/SqlLocalDb.Tests/Examples.cs +++ b/tests/SqlLocalDb.Tests/Examples.cs @@ -34,7 +34,7 @@ public async Task Create_A_Sql_LocalDB_Instance() await using (SqlConnection connection = instance.CreateConnection()) { - connection.Open(); + await connection.OpenAsync(); // Use the SQL connection... } @@ -49,7 +49,7 @@ public async Task Create_A_Temporary_Sql_LocalDB_Instance() using TemporarySqlLocalDbInstance instance = localDB.CreateTemporaryInstance(deleteFiles: true); await using var connection = new SqlConnection(instance.ConnectionString); - connection.Open(); + await connection.OpenAsync(); // Use the SQL connection... } @@ -76,7 +76,7 @@ public async Task Use_With_Dependency_Injection() } await using SqlConnection connection = instance.CreateConnection(); - connection.Open(); + await connection.OpenAsync(); // Use the SQL connection... } diff --git a/tests/SqlLocalDb.Tests/ISqlLocalDbInstanceManagerExtensionsTests.cs b/tests/SqlLocalDb.Tests/ISqlLocalDbInstanceManagerExtensionsTests.cs index ab635bf6..d611bdf0 100644 --- a/tests/SqlLocalDb.Tests/ISqlLocalDbInstanceManagerExtensionsTests.cs +++ b/tests/SqlLocalDb.Tests/ISqlLocalDbInstanceManagerExtensionsTests.cs @@ -47,7 +47,7 @@ public async Task CreateConnection_Creates_A_Sql_Connection() actual.State.ShouldBe(ConnectionState.Closed); await actual.OpenAsync(); - actual.Close(); + await actual.CloseAsync(); } [Fact] From 995a8b29449a64b3b2a6c1a66ec06bda7d1cfbc3 Mon Sep 17 00:00:00 2001 From: martincostello Date: Thu, 4 Nov 2021 16:09:27 +0000 Subject: [PATCH 27/29] Update to .NET 6 Use the final RTM version of .NET 6. --- Directory.Build.props | 6 +----- Directory.Packages.props | 12 ++++++------ NuGet.config | 6 ++++++ global.json | 2 +- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index f9771b55..00690e01 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -23,11 +23,7 @@ latest true en-US - - $(NoWarn);CA1848 - $(NoWarn);CA1054;CA2234 + $(NoWarn);CA1054;CA1848;CA2234 $(NoWarn);SA0001 enable Apache-2.0 diff --git a/Directory.Packages.props b/Directory.Packages.props index bf047983..88c2be8a 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -7,7 +7,7 @@ - + @@ -28,14 +28,14 @@ - - + + - - - + + + diff --git a/NuGet.config b/NuGet.config index 21cb6efa..30b3aa23 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,6 +1,12 @@ + + + + + + diff --git a/global.json b/global.json index bd7abc87..5f65cfd2 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "6.0.100-rc.2.21505.57", + "version": "6.0.100", "allowPrerelease": false, "rollForward": "latestMajor" } From 251cff04f41289a2d62ab5b9f69a7aac012feef3 Mon Sep 17 00:00:00 2001 From: martincostello Date: Thu, 4 Nov 2021 16:10:29 +0000 Subject: [PATCH 28/29] dotnet format Run dotnet format on the solution. --- src/SqlLocalDb/ISqlLocalDbApiExtensions.cs | 2 +- src/SqlLocalDb/ISqlLocalDbInstanceManager.cs | 2 +- src/SqlLocalDb/Interop/IRegistry.cs | 2 +- src/SqlLocalDb/Interop/SafeLibraryHandle.cs | 2 +- src/SqlLocalDb/Interop/WindowsRegistry.cs | 2 +- src/SqlLocalDb/Properties/AssemblyInfo.cs | 2 +- src/SqlLocalDb/SqlLocalDbErrors.cs | 2 +- src/TestApp/Properties/AssemblyInfo.cs | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/SqlLocalDb/ISqlLocalDbApiExtensions.cs b/src/SqlLocalDb/ISqlLocalDbApiExtensions.cs index 40689cb0..885c050c 100644 --- a/src/SqlLocalDb/ISqlLocalDbApiExtensions.cs +++ b/src/SqlLocalDb/ISqlLocalDbApiExtensions.cs @@ -1,4 +1,4 @@ -// Copyright (c) Martin Costello, 2012-2018. All rights reserved. +// Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. using System; diff --git a/src/SqlLocalDb/ISqlLocalDbInstanceManager.cs b/src/SqlLocalDb/ISqlLocalDbInstanceManager.cs index 1138fc44..bede844e 100644 --- a/src/SqlLocalDb/ISqlLocalDbInstanceManager.cs +++ b/src/SqlLocalDb/ISqlLocalDbInstanceManager.cs @@ -1,4 +1,4 @@ -// Copyright (c) Martin Costello, 2012-2018. All rights reserved. +// Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. namespace MartinCostello.SqlLocalDb; diff --git a/src/SqlLocalDb/Interop/IRegistry.cs b/src/SqlLocalDb/Interop/IRegistry.cs index c1011198..abbec1e5 100644 --- a/src/SqlLocalDb/Interop/IRegistry.cs +++ b/src/SqlLocalDb/Interop/IRegistry.cs @@ -1,4 +1,4 @@ -// Copyright (c) Martin Costello, 2012-2018. All rights reserved. +// Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. namespace MartinCostello.SqlLocalDb.Interop; diff --git a/src/SqlLocalDb/Interop/SafeLibraryHandle.cs b/src/SqlLocalDb/Interop/SafeLibraryHandle.cs index 901e824e..caff79d1 100644 --- a/src/SqlLocalDb/Interop/SafeLibraryHandle.cs +++ b/src/SqlLocalDb/Interop/SafeLibraryHandle.cs @@ -1,4 +1,4 @@ -// Copyright (c) Martin Costello, 2012-2018. All rights reserved. +// Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. using Microsoft.Win32.SafeHandles; diff --git a/src/SqlLocalDb/Interop/WindowsRegistry.cs b/src/SqlLocalDb/Interop/WindowsRegistry.cs index 144785dc..22bf10bb 100644 --- a/src/SqlLocalDb/Interop/WindowsRegistry.cs +++ b/src/SqlLocalDb/Interop/WindowsRegistry.cs @@ -1,4 +1,4 @@ -// Copyright (c) Martin Costello, 2012-2018. All rights reserved. +// Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. using Microsoft.Win32; diff --git a/src/SqlLocalDb/Properties/AssemblyInfo.cs b/src/SqlLocalDb/Properties/AssemblyInfo.cs index 919cbb67..46135ee8 100644 --- a/src/SqlLocalDb/Properties/AssemblyInfo.cs +++ b/src/SqlLocalDb/Properties/AssemblyInfo.cs @@ -1,4 +1,4 @@ -// Copyright (c) Martin Costello, 2012-2018. All rights reserved. +// Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. using System; diff --git a/src/SqlLocalDb/SqlLocalDbErrors.cs b/src/SqlLocalDb/SqlLocalDbErrors.cs index 570a9a2a..78d3684b 100644 --- a/src/SqlLocalDb/SqlLocalDbErrors.cs +++ b/src/SqlLocalDb/SqlLocalDbErrors.cs @@ -1,4 +1,4 @@ -// Copyright (c) Martin Costello, 2012-2018. All rights reserved. +// Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. using System.Diagnostics.CodeAnalysis; diff --git a/src/TestApp/Properties/AssemblyInfo.cs b/src/TestApp/Properties/AssemblyInfo.cs index c0377fe0..7e893c41 100644 --- a/src/TestApp/Properties/AssemblyInfo.cs +++ b/src/TestApp/Properties/AssemblyInfo.cs @@ -1,4 +1,4 @@ -// Copyright (c) Martin Costello, 2012-2018. All rights reserved. +// Copyright (c) Martin Costello, 2012-2018. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. using System; From 186909198a74fc955b6e36ab0964edd7734c554b Mon Sep 17 00:00:00 2001 From: Martin Costello Date: Mon, 8 Nov 2021 07:48:00 +0000 Subject: [PATCH 29/29] Remove NuGet prerelease feeds Remove the prerelease NuGet feeds for .NET 6. --- NuGet.config | 6 ------ 1 file changed, 6 deletions(-) diff --git a/NuGet.config b/NuGet.config index 30b3aa23..21cb6efa 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,12 +1,6 @@ - - - - - -