UPDATE 2: FIXED THE CODE at the end
I have the abp.io service below with 2 parameters in the constructor instantiated via DI.
One of them, IOutcomeWriter, has 2 implementations.
I'd like to define at runtime which of the implementations of IOutcomeWriter to use.
This is the main service:
public class UCManagerService
: DomainService, IUCManagerService, ITransientDependency {
private readonly IUCInputReader _inputReader;
// This field can have 2 or 3 implementations.
private readonly IOutcomeWriter _outcomeWriter;
public UCManagerService(
IUCInputReader inputReader, IOutcomeWriter outcomeWriter) {
_inputReader = inputReader;
_outcomeWriter = outcomeWriter;
}
public async Task ExecuteAsync() {
// start processing the input and generate the output
var input = _inputReader.GetInput());
// do something
// ...
_outcomeWriter.Write(something);
}
}
The main service is registered in the AbpModule together with with IUCInputReader and the 2 implementations of IOutcomeWriter:
[DependsOn(
typeof(SwiftConverterDomainModule),
typeof(AbpAutofacModule) // <= use Autofac in some way (I don't know how)
)]
public class ProgramAppModule : AbpModule {
public override void ConfigureServices(ServiceConfigurationContext context) {
context.Services.AddTransient<IUCManagerService, UCManagerService>();
context.Services.AddTransient<IUCInputReader, UCInputReader>();
// 2 implementations of IOutcomeWriter
context.Services.AddTransient<IOutcomeWriter, OutcomeWriter1>();
context.Services.AddTransient<IOutcomeWriter, OutcomeWriter2>();
}
}
What I would like is to instantiate UCManagerService sometimes with OutcomeWriter1 and sometimes with OutcomeWriter2, according to some values in appsettings.json:
IList<JobSetting> jobsToSet = _configuration.GetSection("Jobs")
.Get<List<JobSetting>>();
foreach (JobSetting jobToSet in jobsToSet) {
// If jobsToSet.SomeValue == 'MyValue1' following line should have to
// require a IUCManagerService using OutcomeWriter1. If it is
// 'MyValue2' it'd use OutcomeWriter2, and so on:
var service = abpApplication.ServiceProvider.GetRequiredService<IUCManagerService>(); // ???
// do something else with service
// ...
}
Finally, if a tomorrow I add an OutcomeWriter3 I would just like to register it in ProgramAppModule.ConfigureServices(...) and of course use a different key in appsettings.json.
If I understand correctly, you need the IOutcomeWriter to differ based on the currently executed job. In other words, that means that you need to dynamically switch the writer based on its context.
The fact that it you need to change it dynamically, it means that is not a problem that can be solved solely using your DI configuration, because DI configurations are best kept static.
Instead, you need to mix and match a few concepts. First of all, you need a way to set the used job in the context. For instance:
// DI configuration
services.AddScoped<JobContext>();
// Execution of a job
using (var scope = abpApplication.ServiceProvider.CreateScope())
{
var context = scope.GetRequiredService<JobContext>();
context.CurrentJob = typeof(MyFirstJob);
var job = scope.GetRequiredService<MyFirstJob>();
var job.Execute();
}
In this example, JobContext is a class that holds the data that is used during the execution of a certain job. It is registered as Scoped to allow this data to be available for multiple classes within the same scope.
Now using this new JobContext, you can build an adapter for IOutcomeWriter that can forward the incoming call to the right implementation based on its injected JobContext. This might look as follows:
public class JobSpecificOutcomeWriter : IOutcomeWriter
{
private readonly JobContext context;
private readonly IList<JobSetting> settings;
private readonly IEnumerable<IOutcomeWriter> writers;
public JobSpecificOutcomeWriter(
JobContext context,
IList<JobSetting> settings,
IEnumerable<IOutcomeWriter> writers)
{
this.context = context;
this.settings = settings;
this.writers = writers;
}
// Implement all IOutcomeWriter methods by forwarding them to the
// CurrentWriter.
object IOutcomeWriter.SomeMethod(object a) =>
this.CurrentWriter.SomeMethod(a);
private IOutcomeWriter CurrentWriter
{
get
{
// TODO: Based on the current context and the settings,
// select the proper outcome writer from the writers list.
}
}
}
When JobSpecificOutcomeWriter is injected into UCManagerService (or any component for that matter), it transparently allows the proper writer to be used, without the consuming class from knowing about this.
The tricky part, actually, is to now configure your DI container correctly using JobSpecificOutcomeWriter. Depending on which DI Container you use, your mileage might vary and with the MS.DI Container, this is actually quite complicated.
services.AddTransient<IOutcomeWriter>(c =>
new JobSpecificOutcomeWriter(
context: c.GetRequiredService<JobContext>(),
settings: jobsToSet,
writers: new IOutcomeWriter[]
{
c.GetRequiredService<MyFirstJob>(),
c.GetRequiredService<MySecondJob>(),
c.GetRequiredService<MyThirdJob>(),
});
services.AddTransient<MyFirstJob>();
services.AddTransient<MySecondJob>();
services.AddTransient<MyThirdJob>();
Related
We are transitioning from Xamarin.Forms to .Net MAUI but our project uses Prism.Unity.Forms. We have a lot of code that basically uses the IContainer.Resolve() passing in a collection of ParameterOverrides with some primitives but some are interfaces/objects. The T we are resolving is usually a registered View which may or may not be the correct way of doing this but it's what I'm working with and we are doing it in backend code (sometimes a service). What is the correct way of doing this Unity thing in DryIoC? Note these parameters are being set at runtime and may only be part of the parameters a constructor takes in (some may be from already registered dependencies).
Example of the scenario:
//Called from service into custom resolver method
var parameterOverrides = new[]
{
new ParameterOverride("productID", 8675309),
new ParameterOverride("objectWithData", IObjectWithData)
};
//Custom resolver method example
var resolverOverrides = new List<ResolverOverride>();
foreach(var parameterOverride in parameterOverrides)
{
resolverOverrides.Add(parameterOverride);
}
return _container.Resolve<T>(resolverOverrides.ToArray());
You've found out why you don't use the container outside of the resolution root. I recommend not trying to replicate this error with another container but rather fixing it - use handcoded factories:
internal class SomeFactory : IProductViewFactory
{
public SomeFactory( IService dependency )
{
_dependency = dependency ?? throw new ArgumentNullException( nameof(dependency) );
}
#region IProductViewFactory
public IProductView Create( int productID, IObjectWithData objectWithData ) => new SomeProduct( productID, objectWithData, _dependency );
#endregion
#region private
private readonly IService _dependency;
#endregion
}
See this, too:
For dependencies that are independent of the instance you're creating, inject them into the factory and store them until needed.
For dependencies that are independent of the context of creation but need to be recreated for each created instance, inject factories into the factory and store them.
For dependencies that are dependent on the context of creation, pass them into the Create method of the factory.
Also, be aware of potential subtle differences in container behaviours: Unity's ResolverOverride works for the whole call to resolve, i.e. they override parameters of dependencies, too, whatever happens to match by name. This could very well be handled very differently by DryIOC.
First, I would agree with the #haukinger answer to rethink how do you pass the runtime information into the services. The most transparent and simple way in my opinion is by passing it via parameters into the consuming methods.
Second, here is a complete example in DryIoc to solve it head-on + the live code to play with.
using System;
using DryIoc;
public class Program
{
record ParameterOverride(string Name, object Value);
record Product(int productID);
public static void Main()
{
// get container somehow,
// if you don't have an access to it directly then you may resolve it from your service provider
IContainer c = new Container();
c.Register<Product>();
var parameterOverrides = new[]
{
new ParameterOverride("productID", 8675309),
new ParameterOverride("objectWithData", "blah"),
};
var parameterRules = Parameters.Of;
foreach (var po in parameterOverrides)
{
parameterRules = parameterRules.Details((_, x) => x.Name.Equals(po.Name) ? ServiceDetails.Of(po.Value) : null);
}
c = c.With(rules => rules.With(parameters: parameterRules));
var s = c.Resolve<Product>();
Console.WriteLine(s.productID);
}
}
Given I have a factory class responsible for constructing instances of a certain service that has constructor parameters that can only be resolved at runtime, is there a way to leverage container-driven decoration?
Consider the following class which relies on a parameter that is only defined at runtime:
interface IFooService
{
void DoServicyStuff();
}
class MyFooService : IFooService
{
public MyFooService(string somePeskyRuntimeArgument)
{
this.peskyValue = somePeskyRuntimeArgument;
}
public void DoServicyStuff()
{
// do some stuff here with the peskyValue...
}
}
Since the value can only be provided at runtime, we need to move away from the constructor injection and into a method-level parameter passing. This is commonly achieved using a factory implementation like this:
interface IFooServiceFactory
{
IFooService CreateService(string heyItsNowAMethodLevelPeskyParameter);
}
class FooServiceFactory : IFooServiceFactory
{
public IFooService CreateService(string heyItsNowAMethodLevelPeskyParameter)
{
return new MyFooService(heyItsNowAMethodLevelPeskyParameter);
}
}
While this works fine if the intent is to just abstract away the construction of the service, it poses a challenge to decorate the IFooService instance.
For scenarios where no runtime parameter is involved, this can be easily achieved by tapping into the container to provide our service for us. The example below uses the Scrutor library to decorate the interface with a logging decorator implementation:
class FooServiceFactory : IFooServiceFactory
{
private readonly IServiceProvider serviceProvider;
public FooServiceFactory(IServiceProvider serviceProvider)
{
this.serviceProvider = serviceProvider
}
public IFooService CreateService(string heyItsNowAMethodLevelPeskyParameter)
{
return this.serviceProvider.GetRequiredInstance<IFooService>();
}
}
...
services
.AddTransient<IFooService, MyFooService>()
.AddTransient<IFooServiceFactory, FooServiceFactory>()
.Decorate<IFooService, LoggingFooService>();
But since MyFooService takes a primitive value as an argument, we cannot rely on GetRequiredService<T> to obtain the instance, as it will fail to find "a registration for string" when building the concrete class.
Similarly, changing the factory to rely on ActivatorUtilities's .CreateInstance or .CreateFactory methods will end up creating the objects while completely ignoring the container registrations, thus leaving us without any decorator.
I know I have at least 2 options to decorate the objects manually, namely:
Using the factory itself to manually create the decorator:
public IFooService CreateService(string heyItsNowAMethodLevelPeskyParameter)
{
return new LoggingService(
new MyFooService(heyItsNowAMethodLevelPeskyParameter));
}
Using a factory decorator to inject a decorator after the instance is created:
abstract class FooServiceFactoryDecorator : IFooServiceFactory
{
private readonly IFooServiceFactory fooServiceFactory;
protected FooServiceFactory(IFooServiceFactory fooServiceFactory)
{
this.fooServiceFactory = fooServiceFactory;
}
public virtual IFooService CreateService(string heyItsNowAMethodLevelPeskyParameter)
{
return this.fooServiceFactory.CreateService(heyItsNowAMethodLevelPeskyParameter);
}
}
class LoggingFooServiceFactory : FooServiceFactoryDecorator
{
private readonly IFooServiceFactory fooServiceFactory;
public FooServiceFactory(IFooServiceFactory fooServiceFactory)
{
this.fooServiceFactory = fooServiceFactory;
}
public override IFooService CreateService(string heyItsNowAMethodLevelPeskyParameter)
{
return new LoggingFooService(
this.fooServiceFactory.CreateService(heyItsNowAMethodLevelPeskyParameter));
}
}
...
services
.AddTransient<IFooServiceFactory, FooServiceFactory>()
.Decorate<IFooServiceFactory, LoggingFooServiceFactory>()
Neither of these allows me to directly use .Decorate on top of the service interface. The first option works but is heavily coupled (meaning I'd have to keep changing it if I want to add other decorators into the mix), while the second version is less coupled, but still forces me to writing one factory decorator per service decorator and thus leads into a much more complex solution.
Another pain point is dependencies on the decorators themselves (for example, ILogger<T> on the LoggingFooService), which I could potentially solve by leveraging ActivatorUtilities to create the decorators instead of newing them up manually.
I could also potentially generalize the "factory decorator" so that the decoration function is parameterized and thus the class can be reused, but it is still very convoluted and hard to maintain, while also not providing as good a syntax for consumers to add new decorators.
class DecoratedFooServiceFactory<TDecorator> : FooServiceFactoryDecorator
where TDecorator : IFooService
{
private readonly IFooServiceFactory fooServiceFactory;
private readonly IServiceProvider serviceProvider;
public FooServiceFactory(
IFooServiceFactory fooServiceFactory,
IServiceProvider serviceProvider)
{
this.fooServiceFactory = fooServiceFactory;
this.serviceProvider = serviceProvider;
}
public override IFooService CreateService(string heyItsNowAMethodLevelPeskyParameter)
{
return ActivatorUtilities.CreateInstance<TDecorator>(
this.serviceProvider,
this.fooServiceFactory.CreateService(heyItsNowAMethodLevelPeskyParameter));
}
}
...
services
.AddTransient<IFooServiceFactory, FooServiceFactory>()
.Decorate<IFooServiceFactory, DecoratedFooServiceFactory<LoggingFooService>>()
And finally, if I ever want to move away from using a factory and want to change to using the service directly, this will cause a significant setup change where I'd then have to configure all the decorators again in the container directly instead of just removing the factory registration as one normally would do.
How can I use a factory like this, while still keeping the capability of configuring decorators at the container level using the simple Scrutor syntax?
Ok, a couple of disclaimers first:
I agree with Steven here in that this looks like an anti-pattern and you will probably be better off redesigning your code to not require run-time values on service construction.
I additionally want to caution against using scrutor-like Decorate. While much less confident in this than in the first point, I believe hiding logging in decorators is much less convenient in the long run than it seems at first. Or at least that's what I saw after about a year of trying them out.
That said, let's see what can be done.
First, let's put some constraints on where the value is coming from. Specifically, let's say we can have a service providing that value, that looks like this:
public interface IValueProvider
{
string Get();
}
This actually allows us to have quite a bit of range. Implementation of that interface can:
Get value from external API - once or periodically in the background. It can even call it every time Get is called, but this is a very bad idea, as it will make construction asynchronous.
Get value that is stored in memory and allow some other service to update it. Say, expose a 'configuration' endpoint where a user can set a new value every once in a while.
Calculate the value based on some algorithm of your choice.
Once you have this service, you can register it like this:
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IValueProvider, AwesomeValueProvider>();
services.AddSingleton<IFooServiceFactory, FooServiceFactory>();
services.AddTransient<IFooService>(sp =>
{
var factory = sp.GetRequiredService<IFooServiceFactory>();
var valueProvider = sp.GetRequiredService<IValueProvider>();
return factory.Create(valueProvider.Get());
});
}
Hope this helps
I have many AOP libraries that use Castle DynamicProxy with Autofac DI container for logging, auditing, transaction control, etc.
I wonder if there is a way to declare interceptors using the default .NET Core DI container. It will be good to have this flexibility since many .NET Core projects don't use Autofac.
Yes, you can use DynamicProxy using Core DI. I've written up a blog post explaining it at http://codethug.com/2021/03/17/Caching-with-Attributes-in-DotNet-Core5/, but here is the code for it:
Create an attribute
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class CacheAttribute : Attribute
{
public int Seconds { get; set; } = 30;
}
Create an interceptor (requires Castle.Core nuget package)
public class CacheInterceptor : IInterceptor
{
private IMemoryCache _memoryCache;
public CacheInterceptor(IMemoryCache memoryCache)
{
_memoryCache = memoryCache;
}
// Create a cache key using the name of the method and the values
// of its arguments so that if the same method is called with the
// same arguments in the future, we can find out if the results
// are cached or not
private static string GenerateCacheKey(string name,
object[] arguments)
{
if (arguments == null || arguments.Length == 0)
return name;
return name + "--" +
string.Join("--", arguments.Select(a =>
a == null ? "**NULL**" : a.ToString()).ToArray());
}
public void Intercept(IInvocation invocation)
{
var cacheAttribute = invocation.MethodInvocationTarget
.GetCustomAttributes(typeof(CacheAttribute), false)
.FirstOrDefault() as CacheAttribute;
// If the cache attribute is added ot this method, we
// need to intercept this call
if (cacheAttribute != null)
{
var cacheKey = GenerateCacheKey(invocation.Method.Name,
invocation.Arguments);
if (_memoryCache.TryGetValue(cacheKey, out object value))
{
// The results were already in the cache so return
// them from the cache instead of calling the
// underlying method
invocation.ReturnValue = value;
}
else
{
// Get the result the hard way by calling
// the underlying method
invocation.Proceed();
// Save the result in the cache
var options = new MemoryCacheEntryOptions
{
AbsoluteExpirationRelativeToNow =
new System.TimeSpan(hours: 0, minutes: 0,
seconds: cacheAttribute.Seconds)
};
_memoryCache.Set(cacheKey, invocation.ReturnValue,
options);
}
}
else
{
// We don't need to cache the results,
// nothing to see here
invocation.Proceed();
}
}
}
Add an extension method to help register classes in DI:
public static void AddProxiedScoped<TInterface, TImplementation>
(this IServiceCollection services)
where TInterface : class
where TImplementation : class, TInterface
{
// This registers the underlying class
services.AddScoped<TImplementation>();
services.AddScoped(typeof(TInterface), serviceProvider =>
{
// Get an instance of the Castle Proxy Generator
var proxyGenerator = serviceProvider
.GetRequiredService<ProxyGenerator>();
// Have DI build out an instance of the class that has methods
// you want to cache (this is a normal instance of that class
// without caching added)
var actual = serviceProvider
.GetRequiredService<TImplementation>();
// Find all of the interceptors that have been registered,
// including our caching interceptor. (you might later add a
// logging interceptor, etc.)
var interceptors = serviceProvider
.GetServices<IInterceptor>().ToArray();
// Have Castle Proxy build out a proxy object that implements
// your interface, but adds a caching layer on top of the
// actual implementation of the class. This proxy object is
// what will then get injected into the class that has a
// dependency on TInterface
return proxyGenerator.CreateInterfaceProxyWithTarget(
typeof(TInterface), actual, interceptors);
});
}
Add these lines to ConfigureServices in Startup.cs
// Setup Interception
services.AddSingleton(new ProxyGenerator());
services.AddScoped<IInterceptor, CacheInterceptor>(
After that, if you want to use the cache interceptor, you need to do two things:
First, add the attribute to your method
[Cache(Seconds = 30)]
public async Task<IEnumerable<Person>> GetPeopleByLastName(string lastName)
{
return SomeLongRunningProcess(lastName);
}
Second, register the class in DI using the Proxy/Interception:
services.AddProxiedScoped<IPersonRepository, PersonRepository>();
Instead of the normal way without the Proxy/Interception:
services.AddScoped<IPersonRepository, PersonRepository>();
The base .NET Core container does not have any extra features like interceptors. The whole reason the DI container in .NET Core can be swapped out for something like Autofac is so you can move to a different container once you outgrow the default one.
I have an ASP.NET website project that until recent had all code in App_Code folder. It uses Entity Framework 4 as ORM. Application is divided into three "sections" (let's say one for each customer). Each section has it's own database (but same schema). This is due to performance reasons, databases are over 10GB each with millions of rows.
Each time a context object is created a Session variable which holds section ID is called and proprietary connection string is chosen for this context.
It looks like this (following are members of static Connection class):
public static MyEntities GetEntityContext()
{
if (HttpContext.Current.Session["section"] == null)
{
HttpContext.Current.Response.Redirect("~/Login.aspx");
}
var context = new MyEntities(GetEntityConnectionStringForSection((int)HttpContext.Current.Session["section"]);
return context;
}
private static string GetEntityConnectionStringForSection(int section)
{
switch (section)
{
case 1: return ConfigurationManager.ConnectionStrings["entity_1"].ConnectionString;
case 2: return ConfigurationManager.ConnectionStrings["entity_2"].ConnectionString;
case 3: return ConfigurationManager.ConnectionStrings["entity_3"].ConnectionString;
default: return ConfigurationManager.ConnectionStrings["entity_1"].ConnectionString;
}
}
It works very good and also handles situation when session timed out everytime any data access is performed.
Recently as I needed to share DB classes among two websites I moved all DB classes to separate class library and referenced System.Web library which I know is bad practice, but it's working.
Now the next step is to include unit and module tests which as I read is very difficult or impossible when using HttpContext in library, so I want to get rid of System.Web references. What is the best practice for this situation?
I think I can't just pass HttpContext to GetEntityContext() as it is also called from within my entity classes. Although this probably can be refactored. So maybe this is where I should go?
I also wondered if is it possible to somehow pass current section ID to this whole library? It cannot be just static property because as far as I understand it would be common for all users using the application. This should be user-specific.
Reassuming the objective is to make automated testing possible without loosing transparent Connection String choosing and session timeouts handling.
If I do something fundamentally wrong at this stage please also let me know. I can look again at this question tomorrow morning (8.00 am UTC) so please don't be discouraged by my silence till then.
EDIT:
Example of usage of Connection class in the library:
public partial class Store
{
public static List<Store> GetSpecialStores()
{
using (var context = Connection.GetEntityContext())
{
return context.Stores.Where(qq => qq.Type > 0).OrderBy(qq => qq.Code).ToList();
}
}
}
You can declare interface IContextProvider inside your library ans use it to retrieve context. Something like:
public interface IContextProvider
{
MyEntities GetEntityContext();
}
This will make your library testable. In your web project you can inject IContextProvider implementation into your library.
public class WebContextProvider : IContextProvider
{
public MyEntities GetEntityContext()
{
if (HttpContext.Current.Session["section"] == null)
HttpContext.Current.Response.Redirect("~/Login.aspx");
int sectionId = (int)HttpContext.Current.Session["section"];
string connectionString = GetEntityConnectionStringForSection(sectionId);
var context = new MyEntities(connectionString);
return context;
}
private static string GetEntityConnectionStringForSection(int section)
{
switch (section)
{
case 1: return ConfigurationManager.ConnectionStrings["entity_1"].ConnectionString;
case 2: return ConfigurationManager.ConnectionStrings["entity_2"].ConnectionString;
case 3: return ConfigurationManager.ConnectionStrings["entity_3"].ConnectionString;
default: return ConfigurationManager.ConnectionStrings["entity_1"].ConnectionString;
}
}
}
Inject this interface to repositories or other data access classes.
public partial class Store
{
private IContextProvider contextProvider;
public Store(IContextProvider contextProvider)
{
this.contextProvider = contextProvider;
}
public List<Store> GetSpecialStores()
{
using (var context = contextProvider.GetEntityContext())
{
return context.Stores.Where(qq => qq.Type > 0).OrderBy(qq => qq.Code).ToList();
}
}
}
My app has a ProviderFactory static class that has static utility methods passing back static instances of things like a logger. The rest of my app then can just grab a/the reference to the logger from anywhere without having to pass in the logger (common design practice).
So, another part of my app, the DbCacheProvider, has methods that make calls to the logger so internally it gets a reference to the logger from the factory and then issues calls to it.
My question is that using Moq, I want to verify methods on the logger are being called by the methods within the DbCacheProvider. I can do this using dependency injection when I pass a mock logger into the DbCacheProvider as a parameter, but I'm not passing the logger in (not do I want to). So, how would I verify the DbCacheProvider is making calls to the logger?
If you don't want to pass the logger in through the constructor you'd need to change your ProviderFactory while running unit tests to return your mocked logger.
Anyway there are a couple of reasons it's often suggested to set up dependency injection:
Your tests are more straightforward and don't involve finagling with custom factories
IoC frameworks like Unity, Ninject and Autofac make it easy to create objects when their dependencies are set up this way. If you set up all of your objects this way, the framework will do all the heavy lifting of creating the right objects and passing them in for you. The dependency injection is done automatically and won't be a burden for you.
Old question without an answer, I had a similar problem and solved it like this:
I have the following sample code and need to verify that not only was a method called but was called with a specific value.
public interface ILog
{
void Info(string message);
}
public interface ILogFactory
{
ILog GetLogger();
}
This is the class being tested, where the interface items are being injected:
public class NewAction
{
readonly ILogFactory _logger;
public NewAction(ILogFactory logger)
{
_logger = logger;
}
public void Step1()
{
_logger.GetLogger().Info("Step 1");
}
public void Step2()
{
_logger.GetLogger().Info("Step 2");
}
}
This is obviously a very simplistic view of my actual code, but I needed to verify that Step1 and Step2 are behaving as expected and passed the correct values to the Log, this would mean I also needed to ensure they occurred in the right order. My test:
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
// Arrange
var log = new Mock<ILog>();
var factory = new Mock<ILogFactory>();
factory.Setup(l => l.GetLogger()).Returns(log.Object);
// Act
var action = new NewAction(factory.Object);
action.Step1();
action.Step2();
// Assert
factory.Verify(l => l.GetLogger());
log.Verify(l => l.Info(It.Is<string>(s => s == "Step 1")));
log.Verify(l => l.Info(It.Is<string>(s => s == "Step 2")));
}
}
Hope this helps.