diff --git a/src/EFCore.Design/Design/DbContextActivator.cs b/src/EFCore.Design/Design/DbContextActivator.cs index e41a7f54439..51141033347 100644 --- a/src/EFCore.Design/Design/DbContextActivator.cs +++ b/src/EFCore.Design/Design/DbContextActivator.cs @@ -22,11 +22,13 @@ public static class DbContextActivator /// The type to instantiate. /// The application's startup assembly. /// The design-time report handler. + /// Arguments passed to the constructor. /// The newly created object. public static DbContext CreateInstance( [NotNull] Type contextType, [CanBeNull] Assembly startupAssembly = null, - [CanBeNull] IOperationReportHandler reportHandler = null) + [CanBeNull] IOperationReportHandler reportHandler = null, + [CanBeNull] string[] arguments = null) { Check.NotNull(contextType, nameof(contextType)); @@ -34,7 +36,7 @@ public static DbContext CreateInstance( new OperationReporter(reportHandler), contextType.Assembly, startupAssembly ?? contextType.Assembly, - args: Array.Empty()) // TODO: Issue #8332 + args: arguments ?? Array.Empty()) .CreateContext(contextType.FullName); } } diff --git a/src/EFCore.Design/Design/Internal/AppServiceProviderFactory.cs b/src/EFCore.Design/Design/Internal/AppServiceProviderFactory.cs index 57b9b0621dc..360c325b403 100644 --- a/src/EFCore.Design/Design/Internal/AppServiceProviderFactory.cs +++ b/src/EFCore.Design/Design/Internal/AppServiceProviderFactory.cs @@ -44,7 +44,7 @@ public virtual IServiceProvider Create([NotNull] string[] args) _reporter.WriteVerbose(DesignStrings.FindingServiceProvider); return CreateFromHosting(args) - ?? CreateEmptyServiceProvider(); + ?? CreateArgsServiceProvider(args); } private IServiceProvider CreateFromHosting(string[] args) @@ -97,11 +97,13 @@ private IServiceProvider CreateFromHosting(string[] args) } } - private IServiceProvider CreateEmptyServiceProvider() + private IServiceProvider CreateArgsServiceProvider(string[] args) { _reporter.WriteVerbose(DesignStrings.NoServiceProvider); - return new ServiceCollection().BuildServiceProvider(); + return new ServiceCollection() + .AddScoped(typeof(string[]), sp => args) + .BuildServiceProvider(); } } } diff --git a/src/EFCore.Design/Design/OperationExecutor.cs b/src/EFCore.Design/Design/OperationExecutor.cs index 1ccda89c4c9..a0a9dfdc3e3 100644 --- a/src/EFCore.Design/Design/OperationExecutor.cs +++ b/src/EFCore.Design/Design/OperationExecutor.cs @@ -47,6 +47,8 @@ public class OperationExecutor : MarshalByRefObject /// startupTargetName--The assembly name of the startup project. /// projectDir--The target project's root directory. /// rootNamespace--The target project's root namespace. + /// language--The programming language to be used to generate classes. + /// appArgs--Extra arguments passed into the operation. /// /// The . /// The executor arguments. @@ -61,9 +63,7 @@ public OperationExecutor([NotNull] IOperationReportHandler reportHandler, [NotNu _projectDir = (string)args["projectDir"]; _rootNamespace = (string)args["rootNamespace"]; _language = (string)args["language"]; - - // TODO: Flow in from tools (issue #8332) - _designArgs = Array.Empty(); + _designArgs = (string[])args["appArgs"]; var toolsVersion = (string)args["toolsVersion"]; var runtimeVersion = ProductInfo.GetVersion(); diff --git a/src/ef/Commands/CommandBase.cs b/src/ef/Commands/CommandBase.cs index 1bdde78a788..1c708c7352e 100644 --- a/src/ef/Commands/CommandBase.cs +++ b/src/ef/Commands/CommandBase.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System.Collections.Generic; using Microsoft.DotNet.Cli.CommandLine; using Microsoft.EntityFrameworkCore.Tools.Properties; @@ -8,6 +9,8 @@ namespace Microsoft.EntityFrameworkCore.Tools.Commands { internal abstract class CommandBase { + protected string[] RemainingArguments { get; private set; } + public virtual void Configure(CommandLineApplication command) { var verbose = command.Option("-v|--verbose", Resources.VerboseDescription); @@ -15,6 +18,7 @@ public virtual void Configure(CommandLineApplication command) var prefixOutput = command.Option("--prefix-output", Resources.PrefixDescription); command.HandleResponseFiles = true; + RemainingArguments = command.RemainingArguments.ToArray(); command.OnExecute( () => diff --git a/src/ef/Commands/DatabaseDropCommand.cs b/src/ef/Commands/DatabaseDropCommand.cs index b1b076260de..30f73f5ed7c 100644 --- a/src/ef/Commands/DatabaseDropCommand.cs +++ b/src/ef/Commands/DatabaseDropCommand.cs @@ -15,7 +15,7 @@ protected override int Execute() void LogDropCommand(Func resource) { - var result = executor.GetContextInfo(Context.Value()); + var result = executor.GetContextInfo(Context.Value(), RemainingArguments); var databaseName = result["DatabaseName"] as string; var dataSource = result["DataSource"] as string; Reporter.WriteInformation(resource(databaseName, dataSource)); @@ -38,7 +38,7 @@ void LogDropCommand(Func resource) } } - executor.DropDatabase(Context.Value()); + executor.DropDatabase(Context.Value(), RemainingArguments); return base.Execute(); } diff --git a/src/ef/Commands/DatabaseUpdateCommand.cs b/src/ef/Commands/DatabaseUpdateCommand.cs index ce3ec7bbcd4..79edd47626f 100644 --- a/src/ef/Commands/DatabaseUpdateCommand.cs +++ b/src/ef/Commands/DatabaseUpdateCommand.cs @@ -8,7 +8,7 @@ internal partial class DatabaseUpdateCommand { protected override int Execute() { - CreateExecutor().UpdateDatabase(_migration.Value, _connection.Value(), Context.Value()); + CreateExecutor().UpdateDatabase(_migration.Value, _connection.Value(), Context.Value(), RemainingArguments); return base.Execute(); } diff --git a/src/ef/Commands/DbContextInfoCommand.cs b/src/ef/Commands/DbContextInfoCommand.cs index 4dc81b94350..768c8dac278 100644 --- a/src/ef/Commands/DbContextInfoCommand.cs +++ b/src/ef/Commands/DbContextInfoCommand.cs @@ -11,7 +11,7 @@ internal partial class DbContextInfoCommand { protected override int Execute() { - var result = CreateExecutor().GetContextInfo(Context.Value()); + var result = CreateExecutor().GetContextInfo(Context.Value(), RemainingArguments); if (_json.HasValue()) { diff --git a/src/ef/Commands/DbContextScaffoldCommand.cs b/src/ef/Commands/DbContextScaffoldCommand.cs index 1b6d0905ba3..74361d73b7c 100644 --- a/src/ef/Commands/DbContextScaffoldCommand.cs +++ b/src/ef/Commands/DbContextScaffoldCommand.cs @@ -37,7 +37,8 @@ protected override int Execute() _tables.Values, _dataAnnotations.HasValue(), _force.HasValue(), - _useDatabaseNames.HasValue()); + _useDatabaseNames.HasValue(), + RemainingArguments); if (_json.HasValue()) { ReportJsonResults(result); diff --git a/src/ef/Commands/DbContextScriptCommand.cs b/src/ef/Commands/DbContextScriptCommand.cs index 6297713bd37..b42ff0f70c7 100644 --- a/src/ef/Commands/DbContextScriptCommand.cs +++ b/src/ef/Commands/DbContextScriptCommand.cs @@ -13,7 +13,7 @@ internal partial class DbContextScriptCommand protected override int Execute() { var sql = CreateExecutor().ScriptDbContext( - Context.Value()); + Context.Value(), RemainingArguments); if (!_output.HasValue()) { diff --git a/src/ef/Commands/MigrationsAddCommand.cs b/src/ef/Commands/MigrationsAddCommand.cs index 37031581bd5..286e006962f 100644 --- a/src/ef/Commands/MigrationsAddCommand.cs +++ b/src/ef/Commands/MigrationsAddCommand.cs @@ -21,7 +21,7 @@ protected override void Validate() protected override int Execute() { - var files = CreateExecutor().AddMigration(_name.Value, _outputDir.Value(), Context.Value()); + var files = CreateExecutor().AddMigration(_name.Value, _outputDir.Value(), Context.Value(), RemainingArguments); if (_json.HasValue()) { diff --git a/src/ef/Commands/MigrationsListCommand.cs b/src/ef/Commands/MigrationsListCommand.cs index dfd775ece7d..21f686550b1 100644 --- a/src/ef/Commands/MigrationsListCommand.cs +++ b/src/ef/Commands/MigrationsListCommand.cs @@ -13,7 +13,8 @@ internal partial class MigrationsListCommand { protected override int Execute() { - var migrations = CreateExecutor().GetMigrations(Context.Value()).ToList(); + var migrations = CreateExecutor() + .GetMigrations(Context.Value(), RemainingArguments).ToList(); if (_json.HasValue()) { diff --git a/src/ef/Commands/MigrationsRemoveCommand.cs b/src/ef/Commands/MigrationsRemoveCommand.cs index 4b8876b7ad4..60944d842fb 100644 --- a/src/ef/Commands/MigrationsRemoveCommand.cs +++ b/src/ef/Commands/MigrationsRemoveCommand.cs @@ -10,7 +10,7 @@ internal partial class MigrationsRemoveCommand { protected override int Execute() { - var result = CreateExecutor().RemoveMigration(Context.Value(), _force.HasValue()); + var result = CreateExecutor().RemoveMigration(Context.Value(), _force.HasValue(), RemainingArguments); if (_json.HasValue()) { ReportJsonResults(result); diff --git a/src/ef/Commands/MigrationsScriptCommand.cs b/src/ef/Commands/MigrationsScriptCommand.cs index bf91dd20b9d..525f5a700ea 100644 --- a/src/ef/Commands/MigrationsScriptCommand.cs +++ b/src/ef/Commands/MigrationsScriptCommand.cs @@ -16,7 +16,8 @@ protected override int Execute() _from.Value, _to.Value, _idempotent.HasValue(), - Context.Value()); + Context.Value(), + RemainingArguments); if (!_output.HasValue()) { diff --git a/src/ef/IOperationExecutor.cs b/src/ef/IOperationExecutor.cs index 348afdb70f0..626f0d0778c 100644 --- a/src/ef/IOperationExecutor.cs +++ b/src/ef/IOperationExecutor.cs @@ -9,12 +9,12 @@ namespace Microsoft.EntityFrameworkCore.Tools { internal interface IOperationExecutor : IDisposable { - IDictionary AddMigration(string name, string outputDir, string contextType); - IDictionary RemoveMigration(string contextType, bool force); - IEnumerable GetMigrations(string contextType); - void DropDatabase(string contextType); - IDictionary GetContextInfo(string name); - void UpdateDatabase(string migration, string connectionString, string contextType); + IDictionary AddMigration(string name, string outputDir, string contextType, string[] remainingArguments); + IDictionary RemoveMigration(string contextType, bool force, string[] remainingArguments); + IEnumerable GetMigrations(string contextType, string[] remainingArguments); + void DropDatabase(string contextType, string[] remainingArguments); + IDictionary GetContextInfo(string name, string[] remainingArguments); + void UpdateDatabase(string migration, string connectionString, string contextType, string[] remainingArguments); IEnumerable GetContextTypes(); IDictionary ScaffoldContext( @@ -27,10 +27,11 @@ IDictionary ScaffoldContext( IEnumerable tableFilters, bool useDataAnnotations, bool overwriteFiles, - bool useDatabaseNames); + bool useDatabaseNames, + string[] remainingArguments); - string ScriptMigration(string fromMigration, string toMigration, bool idempotent, string contextType); + string ScriptMigration(string fromMigration, string toMigration, bool idempotent, string contextType, string[] remainingArguments); - string ScriptDbContext(string contextType); + string ScriptDbContext(string contextType, string[] remainingArguments); } } diff --git a/src/ef/OperationExecutorBase.cs b/src/ef/OperationExecutorBase.cs index 745e3952910..64e7e52724a 100644 --- a/src/ef/OperationExecutorBase.cs +++ b/src/ef/OperationExecutorBase.cs @@ -82,39 +82,46 @@ private object InvokeOperationImpl(string operationName, IDictionary arguments) return resultHandler.Result; } - public IDictionary AddMigration(string name, string outputDir, string contextType) + public IDictionary AddMigration(string name, string outputDir, string contextType, string[] remainingArguments) => InvokeOperation( "AddMigration", - new Dictionary { ["name"] = name, ["outputDir"] = outputDir, ["contextType"] = contextType }); + new Dictionary + { + ["name"] = name, + ["outputDir"] = outputDir, + ["contextType"] = contextType, + ["appArgs"] = remainingArguments + }); - public IDictionary RemoveMigration(string contextType, bool force) + public IDictionary RemoveMigration(string contextType, bool force, string[] remainingArguments) => InvokeOperation( "RemoveMigration", - new Dictionary { ["contextType"] = contextType, ["force"] = force }); + new Dictionary { ["contextType"] = contextType, ["force"] = force, ["appArgs"] = remainingArguments }); - public IEnumerable GetMigrations(string contextType) + public IEnumerable GetMigrations(string contextType, string[] remainingArguments) => InvokeOperation>( "GetMigrations", - new Dictionary { ["contextType"] = contextType }); + new Dictionary { ["contextType"] = contextType, ["appArgs"] = remainingArguments }); - public void DropDatabase(string contextType) + public void DropDatabase(string contextType, string[] remainingArguments) => InvokeOperation( "DropDatabase", - new Dictionary { ["contextType"] = contextType }); + new Dictionary { ["contextType"] = contextType, ["appArgs"] = remainingArguments }); - public IDictionary GetContextInfo(string name) + public IDictionary GetContextInfo(string name, string[] remainingArguments) => InvokeOperation( "GetContextInfo", - new Dictionary { ["contextType"] = name }); + new Dictionary { ["contextType"] = name, ["appArgs"] = remainingArguments }); - public void UpdateDatabase(string migration, string connectionString, string contextType) + public void UpdateDatabase(string migration, string connectionString, string contextType, string[] remainingArguments) => InvokeOperation( "UpdateDatabase", - new Dictionary + new Dictionary { ["targetMigration"] = migration, ["connectionString"] = connectionString, - ["contextType"] = contextType + ["contextType"] = contextType, + ["appArgs"] = remainingArguments }); public IEnumerable GetContextTypes() @@ -130,7 +137,8 @@ public IDictionary ScaffoldContext( IEnumerable tableFilters, bool useDataAnnotations, bool overwriteFiles, - bool useDatabaseNames) + bool useDatabaseNames, + string[] remainingArguments) => InvokeOperation( "ScaffoldContext", new Dictionary @@ -144,14 +152,16 @@ public IDictionary ScaffoldContext( ["tableFilters"] = tableFilters, ["useDataAnnotations"] = useDataAnnotations, ["overwriteFiles"] = overwriteFiles, - ["useDatabaseNames"] = useDatabaseNames + ["useDatabaseNames"] = useDatabaseNames, + ["appArgs"] = remainingArguments }); public string ScriptMigration( string fromMigration, string toMigration, bool idempotent, - string contextType) + string contextType, + string[] remainingArguments) => InvokeOperation( "ScriptMigration", new Dictionary @@ -159,12 +169,13 @@ public string ScriptMigration( ["fromMigration"] = fromMigration, ["toMigration"] = toMigration, ["idempotent"] = idempotent, - ["contextType"] = contextType + ["contextType"] = contextType, + ["appArgs"] = remainingArguments }); - public string ScriptDbContext(string contextType) + public string ScriptDbContext(string contextType, string[] remainingArguments) => InvokeOperation( "ScriptDbContext", - new Dictionary { ["contextType"] = contextType }); + new Dictionary { ["contextType"] = contextType, ["appArgs"] = remainingArguments }); } } diff --git a/test/EFCore.Design.Tests/Design/DbContextActivatorTest.cs b/test/EFCore.Design.Tests/Design/DbContextActivatorTest.cs index cc905008f59..0773508db76 100644 --- a/test/EFCore.Design.Tests/Design/DbContextActivatorTest.cs +++ b/test/EFCore.Design.Tests/Design/DbContextActivatorTest.cs @@ -15,6 +15,19 @@ public void CreateInstance_works() Assert.IsType(result); } + [ConditionalFact] + public void CreateInstance_can_pass_in_arguments() + { + var result = DbContextActivator.CreateInstance( + typeof(ArgsContext), arguments: new string[] { "Pass", "Me", "In" }); + + Assert.IsType(result); + Assert.Collection(((ArgsContext)result).Args, + s => { Assert.Equal("Pass", s); }, + s => { Assert.Equal("Me", s); }, + s => { Assert.Equal("In", s); }); + } + private class TestContext : DbContext { protected override void OnConfiguring(DbContextOptionsBuilder options) @@ -22,5 +35,20 @@ protected override void OnConfiguring(DbContextOptionsBuilder options) .EnableServiceProviderCaching(false) .UseInMemoryDatabase(nameof(DbContextActivatorTest)); } + + private class ArgsContext : DbContext + { + public string[] Args { get; set; } + + public ArgsContext(string[] args) + { + Args = args; + } + + protected override void OnConfiguring(DbContextOptionsBuilder options) + => options + .EnableServiceProviderCaching(false) + .UseInMemoryDatabase(nameof(DbContextActivatorTest)); + } } }