Skip to content

Commit

Permalink
add ResolveStrategy to make it config options more clear
Browse files Browse the repository at this point in the history
While writing documentation I realized the parameter names
could be confusing.  It wasn't obvious from the names that
a default behavior was being overridden.

This will make it easier to introduce other strategies,
like ResolveOrThrow or Skip.
  • Loading branch information
drewburlingame committed Feb 15, 2020
1 parent c3ee5b8 commit ddf5295
Show file tree
Hide file tree
Showing 9 changed files with 94 additions and 125 deletions.
42 changes: 11 additions & 31 deletions CommandDotNet.IoC.Autofac/AppRunnerConfigurationExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using System;
using Autofac;
using CommandDotNet.Builders;
using CommandDotNet.Execution;

namespace CommandDotNet.IoC.Autofac
Expand All @@ -11,17 +10,11 @@ public static class AppRunnerConfigurationExtensions
/// <param name="appRunner">the <see cref="AppRunner"/></param>
/// <param name="container">the Autofac container to use</param>
/// <param name="runInScope">if provided, the scope will be created at the beginning of the run and disposed at the end</param>
/// <param name="useResolveForArgumentModel">
/// <see cref="IDependencyResolver.TryResolve"/> is the default to resolve <see cref="IArgumentModel"/>s.
/// Set this to true to use <see cref="IDependencyResolver.Resolve"/>.
/// If Resolve is used and returns null, this framework will attempt to
/// instantiate an instance.
/// <param name="argumentModelResolveStrategy">
/// the <see cref="ResolveStrategy"/> used to resolve <see cref="IArgumentModel"/>s.
/// </param>
/// <param name="useTryResolveForCommandClass">
/// <see cref="IDependencyResolver.Resolve"/> is the default to resolve command classes.
/// Set this to true to use <see cref="IDependencyResolver.TryResolve"/>.
/// If Resolve is used and returns null, this framework will attempt to
/// instantiate an instance.
/// <param name="commandClassResolveStrategy">
/// the <see cref="ResolveStrategy"/> used to resolve command classes.
/// </param>
/// <param name="useLegacyInjectDependenciesAttribute">
/// when true, resolve instances for properties marked with [InjectProperty].
Expand All @@ -31,28 +24,15 @@ public static AppRunner UseAutofac(
this AppRunner appRunner,
IContainer container,
Func<CommandContext, IDisposable> runInScope = null,
bool useResolveForArgumentModel = false,
bool useTryResolveForCommandClass = false,
ResolveStrategy argumentModelResolveStrategy = ResolveStrategy.TryResolve,
ResolveStrategy commandClassResolveStrategy = ResolveStrategy.Resolve,
bool useLegacyInjectDependenciesAttribute = false)
{
return appRunner
.UseDependencyResolver(new AutofacResolver(container),
useResolveForArgumentModel: useResolveForArgumentModel,
useTryResolveForCommandClass: useTryResolveForCommandClass,
useLegacyInjectDependenciesAttribute: useLegacyInjectDependenciesAttribute)
.Configure(b =>
{
if (runInScope != null)
{
b.UseMiddleware((context, next) =>
{
using (runInScope(context))
{
return next(context);
}
}, MiddlewareStages.PreTokenize, int.MinValue + 10);
}
});
return appRunner.UseDependencyResolver(new AutofacResolver(container),
runInScope,
argumentModelResolveStrategy,
commandClassResolveStrategy,
useLegacyInjectDependenciesAttribute);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using CommandDotNet.Builders;
using CommandDotNet.Execution;

namespace CommandDotNet.IoC.MicrosoftDependencyInjection
Expand All @@ -10,17 +9,11 @@ public static class AppRunnerConfigurationExtensions
/// <param name="appRunner">the <see cref="AppRunner"/></param>
/// <param name="serviceProvider">the <see cref="IServiceProvider"/> to use</param>
/// <param name="runInScope">if provided, the scope will be created at the beginning of the run and disposed at the end</param>
/// <param name="useResolveForArgumentModel">
/// <see cref="IDependencyResolver.TryResolve"/> is the default to resolve <see cref="IArgumentModel"/>s.
/// Set this to true to use <see cref="IDependencyResolver.Resolve"/>.
/// If Resolve is used and returns null, this framework will attempt to
/// instantiate an instance.
/// <param name="argumentModelResolveStrategy">
/// the <see cref="ResolveStrategy"/> used to resolve <see cref="IArgumentModel"/>s.
/// </param>
/// <param name="useTryResolveForCommandClass">
/// <see cref="IDependencyResolver.Resolve"/> is the default to resolve command classes.
/// Set this to true to use <see cref="IDependencyResolver.TryResolve"/>.
/// If Resolve is used and returns null, this framework will attempt to
/// instantiate an instance.
/// <param name="commandClassResolveStrategy">
/// the <see cref="ResolveStrategy"/> used to resolve command classes.
/// </param>
/// <param name="useLegacyInjectDependenciesAttribute">
/// when true, resolve instances for properties marked with [InjectProperty].
Expand All @@ -30,28 +23,15 @@ public static AppRunner UseMicrosoftDependencyInjection(
this AppRunner appRunner,
IServiceProvider serviceProvider,
Func<CommandContext, IDisposable> runInScope = null,
bool useResolveForArgumentModel = false,
bool useTryResolveForCommandClass = false,
ResolveStrategy argumentModelResolveStrategy = ResolveStrategy.TryResolve,
ResolveStrategy commandClassResolveStrategy = ResolveStrategy.Resolve,
bool useLegacyInjectDependenciesAttribute = false)
{
return appRunner
.UseDependencyResolver(new MicrosoftDependencyInjectionResolver(serviceProvider),
useResolveForArgumentModel: useResolveForArgumentModel,
useTryResolveForCommandClass: useTryResolveForCommandClass,
useLegacyInjectDependenciesAttribute: useLegacyInjectDependenciesAttribute)
.Configure(b =>
{
if (runInScope != null)
{
b.UseMiddleware((context, next) =>
{
using (runInScope(context))
{
return next(context);
}
}, MiddlewareStages.PreTokenize, int.MinValue + 10);
}
});
return appRunner.UseDependencyResolver(new MicrosoftDependencyInjectionResolver(serviceProvider),
runInScope,
argumentModelResolveStrategy,
commandClassResolveStrategy,
useLegacyInjectDependenciesAttribute);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using CommandDotNet.Builders;
using CommandDotNet.Execution;
using SimpleInjector;

Expand All @@ -11,17 +10,11 @@ public static class AppRunnerConfigurationExtensions
/// <param name="appRunner">the <see cref="AppRunner"/></param>
/// <param name="container">the SimpleInjector container to use</param>
/// <param name="runInScope">if provided, the scope will be created at the beginning of the run and disposed at the end</param>
/// <param name="useResolveForArgumentModel">
/// <see cref="IDependencyResolver.TryResolve"/> is the default to resolve <see cref="IArgumentModel"/>s.
/// Set this to true to use <see cref="IDependencyResolver.Resolve"/>.
/// If Resolve is used and returns null, this framework will attempt to
/// instantiate an instance.
/// <param name="argumentModelResolveStrategy">
/// the <see cref="ResolveStrategy"/> used to resolve <see cref="IArgumentModel"/>s.
/// </param>
/// <param name="useTryResolveForCommandClass">
/// <see cref="IDependencyResolver.Resolve"/> is the default to resolve command classes.
/// Set this to true to use <see cref="IDependencyResolver.TryResolve"/>.
/// If Resolve is used and returns null, this framework will attempt to
/// instantiate an instance.
/// <param name="commandClassResolveStrategy">
/// the <see cref="ResolveStrategy"/> used to resolve command classes.
/// </param>
/// <param name="useLegacyInjectDependenciesAttribute">
/// when true, resolve instances for properties marked with [InjectProperty].
Expand All @@ -31,28 +24,15 @@ public static AppRunner UseSimpleInjector(
this AppRunner appRunner,
Container container,
Func<CommandContext, IDisposable> runInScope = null,
bool useResolveForArgumentModel = false,
bool useTryResolveForCommandClass = false,
ResolveStrategy argumentModelResolveStrategy = ResolveStrategy.TryResolve,
ResolveStrategy commandClassResolveStrategy = ResolveStrategy.Resolve,
bool useLegacyInjectDependenciesAttribute = false)
{
return appRunner
.UseDependencyResolver(new SimpleInjectorResolver(container),
useResolveForArgumentModel: useResolveForArgumentModel,
useTryResolveForCommandClass: useTryResolveForCommandClass,
useLegacyInjectDependenciesAttribute: useLegacyInjectDependenciesAttribute)
.Configure(b =>
{
if (runInScope != null)
{
b.UseMiddleware((context, next) =>
{
using (runInScope(context))
{
return next(context);
}
}, MiddlewareStages.PreTokenize, int.MinValue + 10);
}
});
return appRunner.UseDependencyResolver(new SimpleInjectorResolver(container),
runInScope,
argumentModelResolveStrategy,
commandClassResolveStrategy,
useLegacyInjectDependenciesAttribute);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using CommandDotNet.Execution;
using CommandDotNet.FluentValidation;
using CommandDotNet.TestTools;
using CommandDotNet.TestTools.Scenarios;
Expand Down Expand Up @@ -80,7 +81,7 @@ public void Exec_WithInvalidData_PrintsValidationError_UsingValidatorFromDI()
.UseFluentValidation()
.UseDependencyResolver(
new TestDependencyResolver{new PersonValidator()},
useTryResolveForCommandClass: true)
commandClassResolveStrategy: ResolveStrategy.TryResolve)
.VerifyScenario(TestOutputHelper, scenario);
}

Expand All @@ -96,8 +97,8 @@ public void Exec_WithValidData_Succeeds()
new AppRunner<App>()
.UseFluentValidation()
.UseDependencyResolver(
new TestDependencyResolver { new PersonValidator() },
useTryResolveForCommandClass: true)
new TestDependencyResolver { new PersonValidator() },
commandClassResolveStrategy: ResolveStrategy.TryResolve)
.VerifyScenario(TestOutputHelper, scenario);
}

Expand Down Expand Up @@ -135,8 +136,8 @@ public void Exec_WhenValidatorNotRegistered_ValidatorIsCreated()
new AppRunner<App>()
.UseFluentValidation()
.UseDependencyResolver(
new TestDependencyResolver(),
useTryResolveForCommandClass: true)
new TestDependencyResolver(),
commandClassResolveStrategy: ResolveStrategy.TryResolve)
.VerifyScenario(TestOutputHelper, scenario);
}

Expand All @@ -162,7 +163,7 @@ public void Exec_WhenInvalidValidator_PrintsError()
.UseFluentValidation()
.UseDependencyResolver(
new TestDependencyResolver(),
useTryResolveForCommandClass: true)
commandClassResolveStrategy: ResolveStrategy.TryResolve)
.VerifyScenario(TestOutputHelper, scenario);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using CommandDotNet.Execution;
using CommandDotNet.TestTools;
using FluentAssertions;
using Xunit;
Expand Down Expand Up @@ -29,7 +30,7 @@ public void CommandClass_DefaultUses_Resolve()
public void CommandClass_CanConfigureToUse_TryResolve()
{
new AppRunner<App>()
.UseDependencyResolver(new TestDependencyResolver(), useTryResolveForCommandClass: true)
.UseDependencyResolver(new TestDependencyResolver(), commandClassResolveStrategy: ResolveStrategy.TryResolve)
.RunInMem("Do", _testOutputHelper)
.ExitCode.Should().Be(0);
}
Expand All @@ -47,7 +48,7 @@ public void ArgumentModel_DefaultUses_TryResolve()
public void ArgumentModel_CanConfigureToUse_Resolve()
{
Assert.Throws<Exception>(() => new AppRunner<App>()
.UseDependencyResolver(new TestDependencyResolver { new App() }, useResolveForArgumentModel: true)
.UseDependencyResolver(new TestDependencyResolver { new App() }, argumentModelResolveStrategy: ResolveStrategy.Resolve)
.Run(new[] { "Do" }))
.Message.Should().Contain(
"Dependency not registered: CommandDotNet.Tests.CommandDotNet.IoC.ResolveConfigurationTests+ArgModel");
Expand Down
40 changes: 26 additions & 14 deletions CommandDotNet/AppRunnerConfigExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,17 +71,12 @@ public static AppRunner AppendPipedInputToOperandList(this AppRunner appRunner)
/// <summary>Use the <see cref="IDependencyResolver"/> to create the command classes.</summary>
/// <param name="appRunner">the <see cref="AppRunner"/> instance</param>
/// <param name="dependencyResolver">the <see cref="IDependencyResolver"/> to use</param>
/// <param name="useResolveForArgumentModel">
/// <see cref="IDependencyResolver.TryResolve"/> is the default to resolve <see cref="IArgumentModel"/>s.
/// Set this to true to use <see cref="IDependencyResolver.Resolve"/>.
/// If Resolve is used and returns null, this framework will attempt to
/// instantiate an instance.
/// <param name="runInScope">if provided, the scope will be created at the beginning of the run and disposed at the end</param>
/// <param name="argumentModelResolveStrategy">
/// the <see cref="ResolveStrategy"/> used to resolve <see cref="IArgumentModel"/>s.
/// </param>
/// <param name="useTryResolveForCommandClass">
/// <see cref="IDependencyResolver.Resolve"/> is the default to resolve command classes.
/// Set this to true to use <see cref="IDependencyResolver.TryResolve"/>.
/// If Resolve is used and returns null, this framework will attempt to
/// instantiate an instance.
/// <param name="commandClassResolveStrategy">
/// the <see cref="ResolveStrategy"/> used to resolve command classes.
/// </param>
/// <param name="useLegacyInjectDependenciesAttribute">
/// when true, resolve instances for properties marked with [InjectProperty].
Expand All @@ -90,12 +85,29 @@ public static AppRunner AppendPipedInputToOperandList(this AppRunner appRunner)
public static AppRunner UseDependencyResolver(
this AppRunner appRunner,
IDependencyResolver dependencyResolver,
bool useResolveForArgumentModel = false,
bool useTryResolveForCommandClass = false,
Func<CommandContext, IDisposable> runInScope = null,
ResolveStrategy argumentModelResolveStrategy = ResolveStrategy.TryResolve,
ResolveStrategy commandClassResolveStrategy = ResolveStrategy.Resolve,
bool useLegacyInjectDependenciesAttribute = false)
{
return DependencyResolverMiddleware.UseDependencyResolver(appRunner, dependencyResolver,
useResolveForArgumentModel, useTryResolveForCommandClass, useLegacyInjectDependenciesAttribute);
DependencyResolverMiddleware.UseDependencyResolver(appRunner, dependencyResolver,
argumentModelResolveStrategy, commandClassResolveStrategy, useLegacyInjectDependenciesAttribute);

if (runInScope != null)
{
appRunner.Configure(b =>
{
b.UseMiddleware((context, next) =>
{
using (runInScope(context))
{
return next(context);
}
}, MiddlewareStages.PreTokenize, int.MinValue + 10);
});
}

return appRunner;
}

/// <summary>
Expand Down
8 changes: 4 additions & 4 deletions CommandDotNet/Builders/DependencyResolverMiddleware.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,17 @@ namespace CommandDotNet.Builders
internal static class DependencyResolverMiddleware
{
internal static AppRunner UseDependencyResolver(AppRunner appRunner, IDependencyResolver dependencyResolver,
bool useResolveForArgumentModel,
bool useTryResolveForCommandClass,
ResolveStrategy argumentModelResolveStrategy,
ResolveStrategy commandClassResolveStrategy,
bool useLegacyInjectDependenciesAttribute)
{
return appRunner.Configure(c =>
{
c.DependencyResolver = dependencyResolver;
c.Services.Add(new ResolverService
{
UseResolveForArgumentModel = useResolveForArgumentModel,
UseTryResolveForCommandClass = useTryResolveForCommandClass
ArgumentModelResolveStrategy = argumentModelResolveStrategy,
CommandClassResolveStrategy = commandClassResolveStrategy
});
if (useLegacyInjectDependenciesAttribute)
{
Expand Down
15 changes: 15 additions & 0 deletions CommandDotNet/Execution/ResolveStrategy.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using CommandDotNet.Builders;

namespace CommandDotNet.Execution
{
/// <summary>
/// Specifies whether <see cref="IDependencyResolver.Resolve"/> or <see cref="IDependencyResolver.TryResolve"/> is used.
/// When Resolve is used, if the the Resolve method returns null instead of throwing an exception,
/// the framework will attempt to instantiate an instance of the type.
/// </summary>
public enum ResolveStrategy
{
Resolve,
TryResolve
}
}
Loading

0 comments on commit ddf5295

Please sign in to comment.