diff --git a/Neolution.Extensions.DataSeeding.Sample/Neolution.Extensions.DataSeeding.Sample.csproj b/Neolution.Extensions.DataSeeding.Sample/Neolution.Extensions.DataSeeding.Sample.csproj index f44289b..e277add 100644 --- a/Neolution.Extensions.DataSeeding.Sample/Neolution.Extensions.DataSeeding.Sample.csproj +++ b/Neolution.Extensions.DataSeeding.Sample/Neolution.Extensions.DataSeeding.Sample.csproj @@ -1,4 +1,4 @@ - + Exe net6.0 @@ -8,9 +8,10 @@ - + + - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Neolution.Extensions.DataSeeding.Sample/packages.lock.json b/Neolution.Extensions.DataSeeding.Sample/packages.lock.json index 0cfd0a6..33420ad 100644 --- a/Neolution.Extensions.DataSeeding.Sample/packages.lock.json +++ b/Neolution.Extensions.DataSeeding.Sample/packages.lock.json @@ -13,24 +13,37 @@ } }, "Microsoft.Extensions.Configuration.UserSecrets": { + "type": "Direct", + "requested": "[6.0.2, )", + "resolved": "6.0.2", + "contentHash": "q3zRs1RbaNRHvDaooOOdJs4KMbaVg6MJUgPD60p1DuOMDjob5LbbBYRZwdaas/TrkCUZ7vYSBn3EXrrDWY1HSA==", + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "6.0.1", + "Microsoft.Extensions.Configuration.Json": "6.0.1", + "Microsoft.Extensions.FileProviders.Abstractions": "6.0.1", + "Microsoft.Extensions.FileProviders.Physical": "6.0.1" + } + }, + "Microsoft.Extensions.Logging": { "type": "Direct", "requested": "[6.0.1, )", "resolved": "6.0.1", - "contentHash": "Fy8yr4V6obi7ZxvKYI1i85jqtwMq8tqyxQVZpRSkgeA8enqy/KvBIMdcuNdznlxQMZa72mvbHqb7vbg4Pyx95w==", + "contentHash": "k6tbYaHrqY9kq7p5FfpPbddY1OImPCpXQ/PGcED6N9s5ULRp8n1PdmMzsIwIzCnhIS5bs06G/lO9LfNVpUj8jg==", "dependencies": { - "Microsoft.Extensions.Configuration.Abstractions": "6.0.0", - "Microsoft.Extensions.Configuration.Json": "6.0.0", - "Microsoft.Extensions.FileProviders.Abstractions": "6.0.0", - "Microsoft.Extensions.FileProviders.Physical": "6.0.0" + "Microsoft.Extensions.DependencyInjection": "6.0.2", + "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0", + "Microsoft.Extensions.Logging.Abstractions": "6.0.4", + "Microsoft.Extensions.Options": "6.0.1", + "System.Diagnostics.DiagnosticSource": "6.0.2" } }, "Neolution.CodeAnalysis": { "type": "Direct", - "requested": "[3.1.2, )", - "resolved": "3.1.2", - "contentHash": "pdKfYvkYwLD8/CIQdJrVFHXcOTX+7uHHxcJSqtzGx05BGgN3rSEC+Fd7SRQtr5x3Q0gfOYoMhemoz+1l6NeUpA==", + "requested": "[3.2.1, )", + "resolved": "3.2.1", + "contentHash": "AQDkBJ9e6TrnhpwTtf4KrwlAPBLy77I5XkNey586nN2IFfjk1LVwBwvOcjORD1dSNtEhOf69JQjdmiMf54C90w==", "dependencies": { - "SonarAnalyzer.CSharp": "8.56.0.67649", + "SonarAnalyzer.CSharp": "9.20.0.85982", "StyleCop.Analyzers.Unstable": "1.2.0.556" } }, @@ -83,19 +96,19 @@ }, "Microsoft.Extensions.Configuration": { "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "tq2wXyh3fL17EMF2bXgRhU7JrbO3on93MRKYxzz4JzzvuGSA1l0W3GI9/tl8EO89TH+KWEymP7bcFway6z9fXg==", + "resolved": "6.0.2", + "contentHash": "2dpWx3Lxqq1lzLa9pY4lTOl6xg7VL45z0oe3r1xfXM0nQzR9XpuuMdk54B1LrC/AsyKbOukry+pdoQ7M7e/ezg==", "dependencies": { - "Microsoft.Extensions.Configuration.Abstractions": "6.0.0", - "Microsoft.Extensions.Primitives": "6.0.0" + "Microsoft.Extensions.Configuration.Abstractions": "6.0.1", + "Microsoft.Extensions.Primitives": "6.0.1" } }, "Microsoft.Extensions.Configuration.Abstractions": { "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "qWzV9o+ZRWq+pGm+1dF+R7qTgTYoXvbyowRoBxQJGfqTpqDun2eteerjRQhq5PQ/14S+lqto3Ft4gYaRyl4rdQ==", + "resolved": "6.0.1", + "contentHash": "+FhuIM7bE3CyzhhIju6K1pmcDAp4ez2PKwx8jnV4dEI/LXXBGdQbDijlaQWqMa1oC38DX390bSshQVaKXioiXA==", "dependencies": { - "Microsoft.Extensions.Primitives": "6.0.0" + "Microsoft.Extensions.Primitives": "6.0.1" } }, "Microsoft.Extensions.Configuration.Binder": { @@ -126,70 +139,66 @@ }, "Microsoft.Extensions.Configuration.FileExtensions": { "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "V4Dth2cYMZpw3HhGw9XUDIijpI6gN+22LDt0AhufIgOppCUfpWX4483OmN+dFXRJkJLc8Tv0Q8QK+1ingT2+KQ==", + "resolved": "6.0.1", + "contentHash": "2jaVZJqN6BvEV9DR/gqOnZUY1jjA/NaUcyJVl7Mp3Uvb9N0YE2uSJ6bdmiKxocsiGZxpfjqBe0SRISCCKhVecw==", "dependencies": { - "Microsoft.Extensions.Configuration": "6.0.0", - "Microsoft.Extensions.Configuration.Abstractions": "6.0.0", - "Microsoft.Extensions.FileProviders.Abstractions": "6.0.0", - "Microsoft.Extensions.FileProviders.Physical": "6.0.0", - "Microsoft.Extensions.Primitives": "6.0.0" + "Microsoft.Extensions.Configuration": "6.0.2", + "Microsoft.Extensions.Configuration.Abstractions": "6.0.1", + "Microsoft.Extensions.FileProviders.Abstractions": "6.0.1", + "Microsoft.Extensions.FileProviders.Physical": "6.0.1", + "Microsoft.Extensions.Primitives": "6.0.1" } }, "Microsoft.Extensions.Configuration.Json": { "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "GJGery6QytCzS/BxJ96klgG9in3uH26KcUBbiVG/coNDXCRq6LGVVlUT4vXq34KPuM+R2av+LeYdX9h4IZOCUg==", + "resolved": "6.0.1", + "contentHash": "1jgLdq/UXJ71TE0toUF5VPn7yYaeyiN9sAdX2EZ6Z5DbUiWUKcMRAS5biExfu/ChYMvlGH/7ZlJijPY0zB1Vhg==", "dependencies": { - "Microsoft.Extensions.Configuration": "6.0.0", - "Microsoft.Extensions.Configuration.Abstractions": "6.0.0", - "Microsoft.Extensions.Configuration.FileExtensions": "6.0.0", - "Microsoft.Extensions.FileProviders.Abstractions": "6.0.0", - "System.Text.Json": "6.0.0" + "Microsoft.Extensions.Configuration": "6.0.2", + "Microsoft.Extensions.Configuration.Abstractions": "6.0.1", + "Microsoft.Extensions.Configuration.FileExtensions": "6.0.1", + "Microsoft.Extensions.FileProviders.Abstractions": "6.0.1", + "System.Text.Json": "6.0.11" } }, "Microsoft.Extensions.DependencyInjection": { "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "k6PWQMuoBDGGHOQTtyois2u4AwyVcIwL2LaSLlTZQm2CYcJ1pxbt6jfAnpWmzENA/wfrYRI/X9DTLoUkE4AsLw==", + "resolved": "6.0.2", + "contentHash": "gWUfUZ2ZDvwiVCxsOMComAhG43xstNWWVjV2takUZYRuDSJjO9Q5/b3tfOSkl5mcVwZAL3RZviRj5ZilxHghlw==", "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0", - "System.Runtime.CompilerServices.Unsafe": "6.0.0" + "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0" } }, "Microsoft.Extensions.DependencyInjection.Abstractions": { "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "xlzi2IYREJH3/m6+lUrQlujzX8wDitm4QGnUu6kUXTQAWPuZY8i+ticFJbzfqaetLA6KR/rO6Ew/HuYD+bxifg==" + "resolved": "8.0.1", + "contentHash": "fGLiCRLMYd00JYpClraLjJTNKLmMJPnqxMaiRzEBIIvevlzxz33mXy39Lkd48hu1G+N21S7QpaO5ZzKsI6FRuA==" }, "Microsoft.Extensions.DependencyModel": { "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "TD5QHg98m3+QhgEV1YVoNMl5KtBw/4rjfxLHO0e/YV9bPUBDKntApP4xdrVtGgCeQZHVfC2EXIGsdpRNrr87Pg==", + "resolved": "8.0.2", + "contentHash": "mUBDZZRgZrSyFOsJ2qJJ9fXfqd/kXJwf3AiDoqLD9m6TjY5OO/vLNOb9fb4juC0487eq4hcGN/M2Rh/CKS7QYw==", "dependencies": { - "System.Buffers": "4.5.1", - "System.Memory": "4.5.4", - "System.Runtime.CompilerServices.Unsafe": "6.0.0", - "System.Text.Encodings.Web": "6.0.0", - "System.Text.Json": "6.0.0" + "System.Text.Encodings.Web": "8.0.0", + "System.Text.Json": "8.0.5" } }, "Microsoft.Extensions.FileProviders.Abstractions": { "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "0pd4/fho0gC12rQswaGQxbU34jOS1TPS8lZPpkFCH68ppQjHNHYle9iRuHeev1LhrJ94YPvzcRd8UmIuFk23Qw==", + "resolved": "6.0.1", + "contentHash": "Kr8S/Uunxsjyhh5D91avbME3pITDrVYp/NACiymemtwhnvxpe82Jmr99cnPqiVridg2nIkcNNRVKzl/iP5/00g==", "dependencies": { - "Microsoft.Extensions.Primitives": "6.0.0" + "Microsoft.Extensions.Primitives": "6.0.1" } }, "Microsoft.Extensions.FileProviders.Physical": { "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "QvkL7l0nM8udt3gfyu0Vw8bbCXblxaKOl7c2oBfgGy4LCURRaL9XWZX1FWJrQc43oMokVneVxH38iz+bY1sbhg==", + "resolved": "6.0.1", + "contentHash": "k9h04ZJiQ7mr4hsLNCUc/CL4AwOAHKq0uam4JBfeZ33XSU5MHxn7l7Vpf+T5sd5HXI7us1MGrkB5awqfg5xyHw==", "dependencies": { - "Microsoft.Extensions.FileProviders.Abstractions": "6.0.0", + "Microsoft.Extensions.FileProviders.Abstractions": "6.0.1", "Microsoft.Extensions.FileSystemGlobbing": "6.0.0", - "Microsoft.Extensions.Primitives": "6.0.0" + "Microsoft.Extensions.Primitives": "6.0.1" } }, "Microsoft.Extensions.FileSystemGlobbing": { @@ -207,27 +216,10 @@ "Microsoft.Extensions.FileProviders.Abstractions": "6.0.0" } }, - "Microsoft.Extensions.Localization.Abstractions": { - "type": "Transitive", - "resolved": "6.0.16", - "contentHash": "eRCoZcG/6YqGJQrYziPOc2SmbgJq2ZtP6A9dnvc+9QBDvBHMQZLijpX68NbjGP4OlBpVId512uyuB72boOofuA==" - }, - "Microsoft.Extensions.Logging": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "eIbyj40QDg1NDz0HBW0S5f3wrLVnKWnDJ/JtZ+yJDFnDj90VoPuoPmFkeaXrtu+0cKm5GRAwoDf+dBWXK0TUdg==", - "dependencies": { - "Microsoft.Extensions.DependencyInjection": "6.0.0", - "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0", - "Microsoft.Extensions.Logging.Abstractions": "6.0.0", - "Microsoft.Extensions.Options": "6.0.0", - "System.Diagnostics.DiagnosticSource": "6.0.0" - } - }, "Microsoft.Extensions.Logging.Abstractions": { "type": "Transitive", - "resolved": "6.0.3", - "contentHash": "SUpStcdjeBbdKjPKe53hVVLkFjylX0yIXY8K+xWa47+o1d+REDyOMZjHZa+chsQI1K9qZeiHWk9jos0TFU7vGg==" + "resolved": "6.0.4", + "contentHash": "K14wYgwOfKVELrUh5eBqlC8Wvo9vvhS3ZhIvcswV2uS/ubkTRPSQsN557EZiYUSSoZNxizG+alN4wjtdyLdcyw==" }, "Microsoft.Extensions.Logging.Configuration": { "type": "Transitive", @@ -246,11 +238,11 @@ }, "Microsoft.Extensions.Options": { "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "dzXN0+V1AyjOe2xcJ86Qbo233KHuLEY0njf/P2Kw8SfJU+d45HNS2ctJdnEnrWbM9Ye2eFgaC5Mj9otRMU6IsQ==", + "resolved": "6.0.1", + "contentHash": "v5rh5jRcLBOKOaLVyYCm4TY/RoJlxWsW7N2TAPkmlHe55/0cB0Syp979x4He1+MIXsaTvJl1WOc7b1D1PSsO3A==", "dependencies": { "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0", - "Microsoft.Extensions.Primitives": "6.0.0" + "Microsoft.Extensions.Primitives": "6.0.1" } }, "Microsoft.Extensions.Options.ConfigurationExtensions": { @@ -267,21 +259,8 @@ }, "Microsoft.Extensions.Primitives": { "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "9+PnzmQFfEFNR9J2aDTfJGGupShHjOuGw4VUv+JB044biSHrnmCIMD+mJHmb2H7YryrfBEXDurxQ47gJZdCKNQ==", - "dependencies": { - "System.Runtime.CompilerServices.Unsafe": "6.0.0" - } - }, - "Microsoft.NETCore.Platforms": { - "type": "Transitive", - "resolved": "1.0.1", - "contentHash": "2G6OjjJzwBfNOO8myRV/nFrbTw5iA+DEm0N+qUqhrOmaVtn4pC77h38I1jsXGw5VH55+dPfQsqHD0We9sCl9FQ==" - }, - "Microsoft.NETCore.Targets": { - "type": "Transitive", - "resolved": "1.0.1", - "contentHash": "rkn+fKobF/cbWfnnfBOQHKVKIOpxMZBvlSHkqDWgBpwGDcLRduvs3D9OLGeV6GWGvVwNlVi2CBbTjuPmtHvyNw==" + "resolved": "6.0.1", + "contentHash": "zyJfttJduuQbGEsd/TgerUEdgzHgUn/6oFgeaE04DKUMs7bbzckV7Ci1QZxf/VyQAlG41gR/GjecEScuYoHCUg==" }, "NLog": { "type": "Transitive", @@ -300,77 +279,27 @@ }, "Scrutor": { "type": "Transitive", - "resolved": "4.1.0", - "contentHash": "qZ8GKk9qpD7/ohBrxAz36W8D4smGvnkBhtAvD1c6y8jG3rH0hgt/W4vJEcAOVsZME6Rl1cemiuTZjC4cmEP02g==", - "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0", - "Microsoft.Extensions.DependencyModel": "6.0.0" - } - }, - "SimpleInjector": { - "type": "Transitive", - "resolved": "5.4.0", - "contentHash": "aI00zZSTPl/NaNUvcMqnMQa0q2qMePrVqFc3LDx+fFsMb+eGZOiPDHtFaCW+EKExDqfKxpoJKvacq7JOEFK/HQ==", - "dependencies": { - "System.ComponentModel": "4.0.1" - } - }, - "SimpleInjector.Integration.ServiceCollection": { - "type": "Transitive", - "resolved": "5.5.0", - "contentHash": "+WhjLRtJ6zSSfQRDk71d+RXIkVThfEzNJPmOGCA1O6q2a/srhZxG+wGMhqAK5K2E0fn9ea1w3zB/wxyWpjrbaQ==", + "resolved": "6.1.0", + "contentHash": "m4+0RdgnX+jeiaqteq9x5SwEtuCjWG0KTw1jBjCzn7V8mCanXKoeF8+59E0fcoRbAjdEq6YqHFCmxZ49Kvqp3g==", "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0", - "Microsoft.Extensions.Hosting.Abstractions": "6.0.0", - "Microsoft.Extensions.Localization.Abstractions": "6.0.16", - "Microsoft.Extensions.Logging.Abstractions": "6.0.3", - "SimpleInjector": "5.4.0" + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.1", + "Microsoft.Extensions.DependencyModel": "8.0.2" } }, "SonarAnalyzer.CSharp": { "type": "Transitive", - "resolved": "8.56.0.67649", - "contentHash": "u5klyn4PBAOe38/CoPbxGjuMqJQ5K0M7SA17H2DHgHyQ+neSU+abneRGjSQSVD76kbYXzG7E1/KQwTuj+nnMZw==" + "resolved": "9.20.0.85982", + "contentHash": "c0IYtFg4mYusTafTy0Bs5wev45vRKNShkuoWyQyPMbC6imEFHL7tY/7xbbUJd6JNLYx5vP8wyi2LgiBsMHqb2Q==" }, "StyleCop.Analyzers.Unstable": { "type": "Transitive", "resolved": "1.2.0.556", "contentHash": "zvn9Mqs/ox/83cpYPignI8hJEM2A93s2HkHs8HYMOAQW0PkampyoErAiIyKxgTLqbbad29HX/shv/6LGSjPJNQ==" }, - "System.Buffers": { - "type": "Transitive", - "resolved": "4.5.1", - "contentHash": "Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg==" - }, - "System.ComponentModel": { - "type": "Transitive", - "resolved": "4.0.1", - "contentHash": "oBZFnm7seFiVfugsIyOvQCWobNZs7FzqDV/B7tx20Ep/l3UUFCPDkdTnCNaJZTU27zjeODmy2C/cP60u3D4c9w==", - "dependencies": { - "System.Runtime": "4.1.0" - } - }, "System.Diagnostics.DiagnosticSource": { "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "frQDfv0rl209cKm1lnwTgFPzNigy2EKk1BS3uAvHvlBVKe5cymGyHO+Sj+NLv5VF/AhHsqPIUUwya5oV4CHMUw==", - "dependencies": { - "System.Runtime.CompilerServices.Unsafe": "6.0.0" - } - }, - "System.Memory": { - "type": "Transitive", - "resolved": "4.5.4", - "contentHash": "1MbJTHS1lZ4bS4FmsJjnuGJOu88ZzTT2rLvrhW7Ygic+pC0NWA+3hgAen0HRdsocuQXCkUTdFn9yHJJhsijDXw==" - }, - "System.Runtime": { - "type": "Transitive", - "resolved": "4.1.0", - "contentHash": "v6c/4Yaa9uWsq+JMhnOFewrYkgdNHNG2eMKuNqRn8P733rNXeRCGvV5FkkjBXn2dbVkPXOsO0xjsEeM1q2zC0g==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.0.1", - "Microsoft.NETCore.Targets": "1.0.1" - } + "resolved": "6.0.2", + "contentHash": "6tQaIexFycaotdGn23lf3XJ/eI1GOjQKIvQDRFN9N4pwoNsKnHuXccQ3lnQO6GX8KAb1ic+6ZofJmPdbUVwZag==" }, "System.Runtime.CompilerServices.Unsafe": { "type": "Transitive", @@ -379,25 +308,26 @@ }, "System.Text.Encodings.Web": { "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "Vg8eB5Tawm1IFqj4TVK1czJX89rhFxJo9ELqc/Eiq0eXy13RK00eubyU6TJE6y+GQXjyV5gSfiewDUZjQgSE0w==", + "resolved": "8.0.0", + "contentHash": "yev/k9GHAEGx2Rg3/tU6MQh4HGBXJs70y7j1LaM1i/ER9po+6nnQ6RRqTJn1E7Xu0fbIFK80Nh5EoODxrbxwBQ==", "dependencies": { "System.Runtime.CompilerServices.Unsafe": "6.0.0" } }, "System.Text.Json": { "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "zaJsHfESQvJ11vbXnNlkrR46IaMULk/gHxYsJphzSF+07kTjPHv+Oc14w6QEOfo3Q4hqLJgStUaYB9DBl0TmWg==", + "resolved": "8.0.5", + "contentHash": "0f1B50Ss7rqxXiaBJyzUu9bWFOO2/zSlifZ/UNMdiIpDYe4cY4LQQicP4nirK1OS31I43rn062UIJ1Q9bpmHpg==", "dependencies": { "System.Runtime.CompilerServices.Unsafe": "6.0.0", - "System.Text.Encodings.Web": "6.0.0" + "System.Text.Encodings.Web": "8.0.0" } }, "neolution.extensions.dataseeding": { "type": "Project", "dependencies": { - "SimpleInjector.Integration.ServiceCollection": "[5.5.0, )" + "Microsoft.Extensions.Logging.Abstractions": "[6.0.4, )", + "Scrutor": "[6.1.0, )" } } } diff --git a/Neolution.Extensions.DataSeeding.UnitTests/AbstractSeedTests.cs b/Neolution.Extensions.DataSeeding.UnitTests/AbstractSeedTests.cs new file mode 100644 index 0000000..05c2d20 --- /dev/null +++ b/Neolution.Extensions.DataSeeding.UnitTests/AbstractSeedTests.cs @@ -0,0 +1,102 @@ +namespace Neolution.Extensions.DataSeeding.UnitTests +{ + using System.Linq; + using Microsoft.Extensions.DependencyInjection; + using Microsoft.Extensions.Logging; + using Neolution.Extensions.DataSeeding.Abstractions; + using Neolution.Extensions.DataSeeding.UnitTests.Fakes; + using Neolution.Extensions.DataSeeding.UnitTests.Fakes.MultiTenantSeeds; + using Shouldly; + using Xunit; + using Xunit.Abstractions; + + /// + /// Tests for seeds that inherit from the abstract Seed class. + /// + public class AbstractSeedTests + { + /// + /// The test output helper + /// + private readonly ITestOutputHelper testOutputHelper; + + /// + /// Initializes a new instance of the class. + /// + /// The test output helper. + public AbstractSeedTests(ITestOutputHelper testOutputHelper) + { + this.testOutputHelper = testOutputHelper; + } + + /// + /// Tests that seeds inheriting from the abstract Seed class can be registered and resolved. + /// + [Fact] + public void AbstractSeedCanBeRegisteredAndResolved() + { + // Arrange + var services = this.CreateServiceCollection(); + services.AddDataSeeding(typeof(AbstractSeedTests).Assembly); + services.AddTransient(); + var serviceProvider = services.BuildServiceProvider(); + + // Act & Assert - This should not throw + var abstractSeeds = serviceProvider.GetServices(); + abstractSeeds.ShouldNotBeNull(); + abstractSeeds.ShouldNotBeEmpty(); + + // Verify we can find our specific abstract seed + var abstractSeedExample = abstractSeeds.OfType().FirstOrDefault(); + abstractSeedExample.ShouldNotBeNull(); + } + + /// + /// Tests that the seeder can execute seeds that inherit from the abstract Seed class. + /// + [Fact] + public void SeederCanExecuteAbstractSeeds() + { + // Arrange + var services = this.CreateServiceCollection(); + services.AddDataSeeding(typeof(AbstractSeedTests).Assembly); + services.AddTransient(); + var serviceProvider = services.BuildServiceProvider(); + var dataInitializer = serviceProvider.GetRequiredService(); + + // Act + var result = dataInitializer.Run(); + + // Assert + result.ShouldBeTrue(); + } + + /// + /// Tests that abstract seeds can be manually executed via . + /// + [Fact] + public void AbstractSeedsCanBeManuallyExecuted() + { + // Arrange + var services = this.CreateServiceCollection(); + services.AddDataSeeding(typeof(AbstractSeedTests).Assembly); + var serviceProvider = services.BuildServiceProvider(); + var seeder = serviceProvider.GetRequiredService(); + + // Act & Assert - This should not throw + var seedTask = seeder.SeedAsync(); + seedTask.ShouldNotBeNull(); + } + + /// + /// Creates the service collection. + /// + /// The . + private IServiceCollection CreateServiceCollection() + { + var services = new ServiceCollection(); + services.AddLogging(builder => builder.AddXUnit(this.testOutputHelper)); + return services; + } + } +} diff --git a/Neolution.Extensions.DataSeeding.UnitTests/BasicTests.cs b/Neolution.Extensions.DataSeeding.UnitTests/BasicTests.cs index df97152..eb4d364 100644 --- a/Neolution.Extensions.DataSeeding.UnitTests/BasicTests.cs +++ b/Neolution.Extensions.DataSeeding.UnitTests/BasicTests.cs @@ -3,7 +3,6 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Neolution.Extensions.DataSeeding.UnitTests.Fakes; - using Neolution.Extensions.DataSeeding.UnitTests.Fakes.MultiTenantSeeds; using Shouldly; using Xunit; using Xunit.Abstractions; @@ -35,7 +34,7 @@ public void SeedsCanBeSeededWithLoggingTest() { // Assign var services = this.CreateServiceCollection(); - services.AddDataSeeding(typeof(TenantsSeed).Assembly); + services.AddDataSeeding(typeof(BasicTests).Assembly); services.AddTransient(); var serviceProvider = services.BuildServiceProvider(); var dataInitializer = serviceProvider.GetRequiredService(); @@ -54,7 +53,7 @@ public void SeedsCanBeSeededWithLoggingTest() private IServiceCollection CreateServiceCollection() { var services = new ServiceCollection(); - services.AddLogging(builder => builder.AddXUnit(this.testOutputHelper)); + services.AddLogging(builder => builder.AddXUnit(this.testOutputHelper).SetMinimumLevel(LogLevel.Debug)); return services; } } diff --git a/Neolution.Extensions.DataSeeding.UnitTests/Fakes/MultiTenantSeeds/AbstractSeedExample.cs b/Neolution.Extensions.DataSeeding.UnitTests/Fakes/MultiTenantSeeds/AbstractSeedExample.cs new file mode 100644 index 0000000..1fbdc17 --- /dev/null +++ b/Neolution.Extensions.DataSeeding.UnitTests/Fakes/MultiTenantSeeds/AbstractSeedExample.cs @@ -0,0 +1,38 @@ +namespace Neolution.Extensions.DataSeeding.UnitTests.Fakes.MultiTenantSeeds +{ + using System.Threading.Tasks; + using Microsoft.Extensions.Logging; + using Neolution.Extensions.DataSeeding.Abstractions; + + /// + /// Example seed that inherits from the abstract Seed class instead of implementing ISeed directly. + /// This tests the scenario where users prefer to use the abstract Seed base class. + /// + public class AbstractSeedExample : Seed + { + /// + /// The logger + /// + private readonly ILogger logger; + + /// + /// Initializes a new instance of the class. + /// + /// The logger. + public AbstractSeedExample(ILogger logger) + { + this.logger = logger; + } + + /// + public override async Task SeedAsync() + { + this.logger.LogInformation("AbstractSeedExample.SeedAsync() called"); + + // Example of using the protected SeedAsync() helper method + await SeedAsync().ConfigureAwait(false); + + this.logger.LogInformation("AbstractSeedExample.SeedAsync() completed"); + } + } +} diff --git a/Neolution.Extensions.DataSeeding.UnitTests/Neolution.Extensions.DataSeeding.UnitTests.csproj b/Neolution.Extensions.DataSeeding.UnitTests/Neolution.Extensions.DataSeeding.UnitTests.csproj index 5866df9..46ee334 100644 --- a/Neolution.Extensions.DataSeeding.UnitTests/Neolution.Extensions.DataSeeding.UnitTests.csproj +++ b/Neolution.Extensions.DataSeeding.UnitTests/Neolution.Extensions.DataSeeding.UnitTests.csproj @@ -9,20 +9,19 @@ - - - - + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - + + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/Neolution.Extensions.DataSeeding/Neolution.Extensions.DataSeeding.csproj b/Neolution.Extensions.DataSeeding/Neolution.Extensions.DataSeeding.csproj index 76fe31d..de098f9 100644 --- a/Neolution.Extensions.DataSeeding/Neolution.Extensions.DataSeeding.csproj +++ b/Neolution.Extensions.DataSeeding/Neolution.Extensions.DataSeeding.csproj @@ -6,11 +6,12 @@ - + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/Neolution.Extensions.DataSeeding/Seeder.cs b/Neolution.Extensions.DataSeeding/Seeder.cs index 2aaae1c..4bb8d1f 100644 --- a/Neolution.Extensions.DataSeeding/Seeder.cs +++ b/Neolution.Extensions.DataSeeding/Seeder.cs @@ -2,14 +2,15 @@ { using System; using System.Collections.Generic; + using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Neolution.Extensions.DataSeeding.Abstractions; using Neolution.Extensions.DataSeeding.Internal; /// - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses", Justification = "Resolved as a singleton by DI container")] - internal sealed class Seeder : ISeeder, IAsyncDisposable + [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses", Justification = "Resolved as a singleton by DI container")] + internal sealed class Seeder : ISeeder { /// /// The logger. @@ -53,7 +54,7 @@ public async Task SeedAsync() for (var index = 0; index < sortedSeeds.Count; index++) { var seed = sortedSeeds[index]; - this.logger.LogTrace($"{index + 1}.\t{seed.GetType().Name}"); + this.logger.LogTrace("{Index}.\t{SeedTypeName}", index + 1, seed.GetType().Name); } } @@ -74,12 +75,6 @@ public async Task SeedAsync() await seed.SeedAsync().ConfigureAwait(false); } - /// - public async ValueTask DisposeAsync() - { - await Seeding.Instance.DisposeAsync().ConfigureAwait(false); - } - /// /// Logs the wrap tree in a pretty format. /// @@ -97,7 +92,7 @@ private void LogWrapTree(Wrap wrap, bool last, string indent = "") seedTypeName = seedTypeName[..^suffix.Length]; } - this.logger.LogDebug($"{indent}+- {seedTypeName}"); + this.logger.LogDebug("{Indent}+- {SeedTypeName}", indent, seedTypeName); indent += last ? " " : "| "; for (var i = 0; i < wrap.Wrapped.Count; i++) diff --git a/Neolution.Extensions.DataSeeding/Seeding.cs b/Neolution.Extensions.DataSeeding/Seeding.cs index 860a552..7c39ebe 100644 --- a/Neolution.Extensions.DataSeeding/Seeding.cs +++ b/Neolution.Extensions.DataSeeding/Seeding.cs @@ -4,49 +4,31 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; - using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Neolution.Extensions.DataSeeding.Abstractions; using Neolution.Extensions.DataSeeding.Internal; - using SimpleInjector; - using SimpleInjector.Lifestyles; /// /// The Seeding singleton. /// - internal sealed class Seeding : IAsyncDisposable + internal sealed class Seeding { /// /// The lazy singleton instantiation. /// private static readonly Lazy Lazy = new(() => new Seeding()); - /// - /// The services of the application that is using seeding. - /// - private IServiceCollection? services; - /// /// The assembly that contains the seeds. /// private Assembly? seedsAssembly; - /// - /// The container. - /// - private Container? container; - /// /// The seeds /// private IReadOnlyList seeds = Enumerable.Empty().ToList(); - /// - /// The scope - /// - private Scope? scope; - /// /// Prevents a default instance of the class from being created. /// @@ -64,28 +46,12 @@ private Seeding() /// internal IReadOnlyList Seeds { get; private set; } = Enumerable.Empty().ToList(); - /// - public async ValueTask DisposeAsync() - { - if (this.scope is not null) - { - await this.scope.DisposeAsync().ConfigureAwait(false); - } - - if (this.container is not null) - { - await this.container.DisposeAsync().ConfigureAwait(false); - } - } - /// /// Configures the services with the internal dependency injection container and scans the specified assembly for data seeds. /// - /// The services. /// The assembly containing the implementations. - internal void Configure(IServiceCollection services, Assembly assembly) + public void Configure(Assembly assembly) { - this.services = services; this.seedsAssembly = assembly; } @@ -95,41 +61,27 @@ internal void Configure(IServiceCollection services, Assembly assembly) /// The service provider. internal void UseServiceProvider(IServiceProvider serviceProvider) { - if (this.services is null) - { - throw new InvalidOperationException("The service collection of the application is null. Did you call the Configure() method before calling this?"); - } - if (this.seedsAssembly is null) { throw new InvalidOperationException("Cannot find the assembly containing the seeds. Did you call the Configure() method before calling this?"); } - // Create an isolated DI container just for the seeds but register the services from the application to let the seeds inject them. - this.container = new Container(); - this.services.AddSimpleInjector(this.container); - this.container.Collection.Register(new[] { this.seedsAssembly }, Lifestyle.Transient); - this.container.Collection.Register(new[] { this.seedsAssembly }, Lifestyle.Transient); - - serviceProvider.UseSimpleInjector(this.container); var logger = serviceProvider.GetRequiredService>(); if (logger.IsEnabled(LogLevel.Trace)) { logger.LogTrace("Scan configured assembly for seeds"); - logger.LogTrace($"Assembly full name: '{this.seedsAssembly?.FullName}'"); + logger.LogTrace("Assembly full name: '{SeedsAssemblyFullName}'", this.seedsAssembly.FullName); } - // Always verify the container to avoid some runtime headaches - this.container.Verify(); - - // Open scope for container and resolve all seeds that are registered - this.scope = AsyncScopedLifestyle.BeginScope(this.container); - this.Seeds = this.container.GetAllInstances().ToList(); - this.seeds = this.container.GetAllInstances().ToList(); + // Resolve all seeds that are registered + this.Seeds = serviceProvider.GetServices().ToList(); + this.seeds = serviceProvider.GetServices().ToList(); - logger.LogDebug($"{this.Seeds.Count} seeds have been found and loaded"); - logger.LogDebug($"Seeding instance ready"); + logger.LogDebug("{SeedsCount} seeds have been found and loaded", this.Seeds.Count + this.seeds.Count); + logger.LogTrace("{SeedCount} ISeed implementations found", this.Seeds.Count); + logger.LogTrace("{SeedCount} Seed implementations found", this.seeds.Count); + logger.LogDebug("Seeding instance ready"); } /// diff --git a/Neolution.Extensions.DataSeeding/ServiceCollectionExtensions.cs b/Neolution.Extensions.DataSeeding/ServiceCollectionExtensions.cs index 8ba4985..96db566 100644 --- a/Neolution.Extensions.DataSeeding/ServiceCollectionExtensions.cs +++ b/Neolution.Extensions.DataSeeding/ServiceCollectionExtensions.cs @@ -16,8 +16,22 @@ public static class ServiceCollectionExtensions /// The assembly. public static void AddDataSeeding(this IServiceCollection services, Assembly assembly) { - services.AddSingleton(); - Seeding.Instance.Configure(services, assembly); + services.AddTransient(); + Seeding.Instance.Configure(assembly); + + // Register ISeed implementations + services.Scan(scan => scan + .FromAssemblies(assembly) + .AddClasses(classes => classes.AssignableTo()) + .AsImplementedInterfaces() + .WithTransientLifetime()); + + // Register Seed implementations + services.Scan(scan => scan + .FromAssemblies(assembly) + .AddClasses(classes => classes.AssignableTo()) + .As() + .WithTransientLifetime()); } } }