Object factory which Creates objects that require dependencies - c#

Currently in code i have used an object factory to return me a processor based of a string tag, which has severed its purpose up until now.
using Core;
using Data;
public static class TagProcessorFactory
{
public static ITagProcessor GetProcessor(string tag)
{
switch (tag)
{
case "gps0":
return new GpsTagProcessor();
case "analog_manager":
return new AnalogManagerTagProcessor();
case "input_manager":
return new InputManagerTagProcessor();
case "j1939":
return new J1939TagProcessor(new MemcachedProvider(new[] { "localhost" }, "DigiGateway"), new PgnRepository());
default:
return new UnknownTagProcessor();
}
}
}
Calling Code
var processor = TagProcessorFactory.GetProcessor(tag.Name);
if (!(processor is UnknownTagProcessor))
{
var data = processor.Process(unitId, tag.Values);
Trace.WriteLine("Tag <{0}> processed. # of IO Items => {1}".FormatWith(tag.Name, data.Count()));
}
as you can see one of my items has dependencies and im trying to execute testing code and i want to pass in mock repositories and cache providers but i can seem to think of a way to do this.
Is this a bad design or anyone have any ideas to fix it to make my factory testable?
Thanks

Since you are using Autofac, you can take advantage of the lookup relationship type:
public class Foo
{
private readonly IIndex<string, ITagProcessor> _tagProcessorIndex;
public Foo(IIndex<string, ITagProvider> tagProcessorIndex)
{
_tagProcessorIndex = tagProcessorIndex;
}
public void Process(int unitId, Tag tag)
{
ITagProcessor processor;
if(_tagProcessorIndex.TryGetValue(tag.Name, out processor))
{
var data = processor.Process(unitId, tag.Values);
Trace.WriteLine("Tag <{0}> processed. # of IO Items => {1}".FormatWith(tag.Name, data.Count()));
}
}
}
See the TypedNamedAndKeysServices wiki article for more information. To register the various processors, you would associate each with its key:
builder.RegisterType<GpsTagProcessor>().Keyed<ITagProcessor>("gps0");
builder.RegisterType<AnalogManagerTagProcessor>().Keyed<ITagProcessor>("analog_manager");
builder.RegisterType<InputManagerTagProcessor>().Keyed<ITagProcessor>("input_manager");
builder
.Register(c => new J1939TagProcessor(new MemcachedProvider(new[] { "localhost" }, new PgnRepository()))
.Keyed<ITagProcessor>("j1939");
Notice we don't register UnknownTagProcessor. That was a signal to the caller of the factory that no processor was found for the tag, which we express using TryGetValue instead.

Using something like StructureMap you could use the ObjectFactory which, when configured would return you a named concrete instance.
http://structuremap.net/structuremap/index.html

I suggest you look through another SO post. It solves several problems at once, including how to replace contructor values - without a mess. Specifically, the parameters to the constructor simply become static fields of a "Context" class, which are read by the constructor of the interior class.

Related

Autofac Named Instance - Define Default Instance if Not Found

I'm using Autofac to register named instances. I have to translate xml transactions into objects.
First, I have an enum.
public enum TransactionType
{
Unknown = 0,
[XmlNode("MyNodeA")]
TypeA = 1,
[XmlNode("MyNodeA")]
TypeB = 2
}
I have a method that creates an IDictionary<string, TransactionType> using the XmlNode attribute on the enum.
Here is my autofac mapping
var mappings = TransactionTypeHelper.GetDictionary();
foreach (var mapping in mappings)
{
builder.Register(ctx => {
return mapping.Key;
})
.Named<TransactionType>(mapping.Value)
.InstancePerLifetimeScope();
}
Then, I have a TransactionTypeFactory for getting the TransactionType based on the xml node.
public TransactionType GetTransactionType(string rootNode)
{
return _container.Resolve<TransactionType>(rootNode?.ToLower());
}
My problem is that I want to pass through any unknown xml nodes as unknown transactions so that I can process new transactions without making any code changes. The problem is that _container.Resolve throws an error if the node passed in has not been registered.
What I want to do is make autofac return the enum default if the named instance is not found instead of throwing an error. The funny thing is, I have unit tests where this container is mocked, and they all pass, but Autofac specifically blows up on this call.
I know this question is rather old, but I'd like to share a solution I have learned in the meantime in the hopes it will help someone with the same issue.
With autofac, you can register a function that can resolve using logic.
First, you would register each named instance. In the question I was doing this with a helper and iterating through a collection, but the essence is to map each value of the enum to an instance.
builder.Register<TransactionAClass>(ctx =>
{
//get any instances required by ConcreteClass from the ctx here and pass into the constructor
return new TransactionAClass();
})
.Named<Interfaces.ITransactionInterface>($"{TransactionType.TypeA:f}")
.InstancePerLifetimeScope();
Once you have all your registrations for known values, then we register a resolver function.
builder.Register<Func<TransactionType, Interfaces.ITransactionInterface>>(ctx =>
{
//you must resolve the context this way before being able to resolve other types
var context = ctx.Resolve<IComponentContext>();
//get the registered named instance
return (type) =>
{
var concrete = context.ResolveNamed<Interfaces.ITransactionInterface>($"{type:f}");
if (concrete == null)
{
//return a default class or throw an exception if a valid registration is not found
return new TransactionAClass();
}
return concrete;
}
});
Then, you can use the resolver like this
public class MyClass
{
private readonly ITransactionInterface transaction;
public MyClass(Func<TransactionType, Interfaces.ITransactionInterface> transactionResolver)
{
transaction = transactionResolver.Invoke(TransactionType.TypeA);
}
}

Autofac parameterized instantiation that resolves differently for different parameters

I'm using Autofac with ASP.NET Core.
My dependency is a Reporter:
public class Reporter {
public Reporter (bool doLogging) { DoLogging = doLogging ; }
public string DoLogging { get; set; }
// other stuff
}
I need to use it like this:
public class Foo
{
public Foo(Func<bool, Reporter> reporterFactory) { _reporterFactory = reporterFactory; }
private readonly Func<bool, Reporter> _reporterFactory;
}
And I want it to resolve like this:
_reporterFactory(false) ---> equivalent to ---> new Reporter(false)
_reporterFactory(true) ---> equivalent to ---> new Reporter(true)
I want the same instance per request (i.e. Autofac's InstancePerLifetimeScope), for the same bool parameter. When I call _reporterFactory(false) multiple times, I want the same instance. And when I call _reporterFactory(true) multiple times, I want the same instance. But those two instances must be different to each other.
So I register it like this:
builder
.Register<Reporter>((c, p) => p.TypedAs<bool>() ? new Reporter(true): new Person(false))
.As<Reporter>()
.InstancePerLifetimeScope(); // gives "per HTTP request", which is what I need
However, when I resolve I get the same instances regardless of the bool argument:
var reporter = _reporterFactory(false);
var reporterWithLogging = _reporterFactory(true);
Assert.That(reporter, Is.Not.SameAs(reporterWithLogging)); // FAIL!
The documentation for "Parameterized Instantiation" says
resolve the object more than once, you will get the same object instance every time regardless of the different parameters you pass in. Just passing different parameters will not break the respect for the lifetime scope.
Which explains the behavior. So how do I register it correctly?
As mentioned in comments, you could use keyed services to achieve your goal:
builder.Register(c => new Reporter(true)).Keyed<IReporter>(true).InstancePerLifetimeScope();
builder.Register(c => new Reporter(false)).Keyed<IReporter>(false).InstancePerLifetimeScope();
The thing is, if you want to inject it to another class, you would have to inject it with IIndex<bool, IReporter>:
public class Foo
{
public Foo(IIndex<bool, IReporter> reporters)
{
var withLogging = reporters[true];
var withoutLogging = reporters[false];
}
}
IIndex is Autofac's interface, which makes your component tight coupled with the container, and this may not be desirable. To avoid this, you could additionally register the factory, like this:
builder.Register<Func<bool, IReporter>>((c,p) => withLogging => c.ResolveKeyed<IReporter>(withLogging)).InstancePerLifetimeScope();
public class Foo
{
public Foo(Func<bool, IReporter> reporters)
{
var withLogging = reporters(true);
var withoutLogging = reporters(false);
}
}
Now you have the working solution without coupling to the container itself.

Autofac properties on request

I have a service that depends on other services for example
OrderProvider(IOrderService service) {
}
That is a direct dependant so having it in the constructor is fine.
There are some other methods that require other services, so I have been handling these with properties, for example, I may need to get the Stock for an Order:
private IStockService _stockService;
public IStockService StockService { get { return _stockService ?? (_stockService = new StockService()); } }
Stock GetStock(string orderNumber) {
return StockService.Get(orderNumber);
}
As you can see, in my old way of doing things the property was only instantiated when requested.
Now I have moved to autofac I would like to set up a similar method, i.e. If a request is only for an Order then only the OrderProvider and the OrderService will be instantiated, but if they request the Stock then all 3 will be instantiated.
I really hope that makes sense.
Autofac allows you to request a Lazy<T> closed over the desired type for scenarios like yours that require delayed instantiation. The first time the Lazy<T>'s value is accessed is when the actual instance will be created.
Example Code
private Lazy<IStockService> _lazyStockService;
public IStockService StockService
{
get { return _lazyStockService.Value; }
}
public OrderProvider( IOrderService service, Lazy<IStockService> lazyStockService )
{
_service = service;
_lazyStockService = lazyStockService;
}
Here's a link to Autofac's docs on this topic
Here's a link to the docs for Lazy<T>

Autofac shared objects require different registrations per controller but InstancePerApiControllerType won't work

As detailed in InstancePerApiControllerType not working, I am unable to use the InstancePerApiControllerType to configure my solution. The answer provided there works so long as I am directly injecting a ConnectionContext into the controller, or otherwise know that a class is only used by a specific controller. Unfortunately that is not the case in my situation:
ControllerA -> EngineA -> RepositoryA -> GenericEntityAccessor
ControllerB -> EngineB -> RepositoryB -> GenericEntityAccessor
The issue is when we come in through ControllerA, GenericEntityAccessor needs "string A" and from ControllerB it needs "string B".
Of course, the real situation is a little more complicated and there are some bad practices such as code that directly "news"-up a ConnectionContext (it's legacy code). I'm currently exploring providing another component that provides the connection string that is injected via Autofac and configured in the controller using Lazy, but the bad practices are causing problems there also (i.e. once I start to change things in the interface, all the dominoes start to fall over and I end up 15 classes later wondering how I got there).
Are there any patterns, techniques, etc. that address this type of thing? I can't imagine it's all that uncommon.
UPDATE:
To provide a few more specifics, since I'm having some trouble getting this to work, in general we have the following hierarchy, showing which scopes I've applied
Controller -> InstancePerApiRequest()
I*Repository -> ?
I*Manager -> ?
I*Builder -> ?
I*Adapter -> ?
ISqlServerConnectionContext -> ?
IConnectionContextCache -> InstancePerApiRequest()
I've got a number of components that directly take ISqlServerConntectionContext and I'm trying to provide it like so:
container.Register(c =>
{
var connectionContextCache = c.Resolve<IConnectionContextCache>();
var connection = (ISqlServerConnectionContext)connectionContextCache.CurrentConnectionContext;
return connection;
}).As<ISqlServerConnectionContext>().InstancePerDependency();
Unfortunately at that point I'm getting a null for CurrectConnectionContext. My guess at this point is I've got some component that isn't rooted from the controller and I'm currently going through the dependencies manually attempting to find it (AFAIK the isn't a way for my to find out which object triggered Autofac to attempt to provide the ISqlServerConnectionContext when I'm debugging).
UPDATE 2:
It turns out I did have some issues where I was registering things improperly, and creating a dependency on ISqlServerConnectionContext for DocumentController, even though it did not have one (this was created through the delegate for something it did depend on).
Now I've got a circular reference that I'm pretty sure I've created myself in the registrations:
container.Register(x =>
{
if (x.IsRegistered<HttpRequestMessage>())
{
var httpRequestMethod = x.Resolve<HttpRequestMessage>();
var tokenHelper = x.Resolve<ITokenHelper>();
var token = tokenHelper.GetToken(httpRequestMethod);
return token ?? new NullMinimalSecurityToken();
}
return new NullMinimalSecurityToken();
}).As<IMinimalSecurityToken>().InstancePerApiRequest();
container.Register(c =>
{
var connectionContextCache = c.Resolve<IConnectionContextCache>();
var token = c.Resolve<IMinimalSecurityToken>();
var connection = (ISqlServerConnectionContext)connectionContextCache.CurrentConnectionContext;
connection.Token = token;
return connection;
}).As<ISqlServerConnectionContext>().InstancePerApiRequest();
The problem is ISqlServerConnectionContext has a property of type IMinimalSecurityToken which is optional, and definitely not used when the ISqlServerConnectionContext is being used to look up IMinimalSecurityToken, which depends on ISqlServerConnectionContext through ITokenHelper.
UPDATE 3:
For completeness, in order to solve my circular reference problem I needed to use named services, and use a SqlServerConnectionContext that did not have the IMinimalSecurityToken property set for the IOAuthTokenManager registration. Now I'm getting the dreaded
No scope with a Tag matching 'AutofacWebRequest' is visible
error, but I think that warrants a new question if I'm not able to solve it.
container.Register(c =>
{
var productId = WellKnownIdentifierFactory.Instance.GetWellKnownProductIdentifier(WellKnownProductIdentifiers.RESTSearchService);
var connectionString = ConfigurationManager.AppSettings[AppSettingsNames.DatabaseConnection];
var newConnectionContext = new SqlServerConnectionContext(connectionString) { ProductID = productId };
newConnectionContext.Open();
return newConnectionContext;
}).Named<ISqlServerConnectionContext>("OAuthTokenConnectionContext").InstancePerApiRequest();
container.Register(c => new SqlServerBuilderFactory(c.ResolveNamed<ISqlServerConnectionContext>("OAuthTokenConnectionContext"))).Named<IBuilderFactory>("OAuthTokenBuilderFactory").InstancePerApiRequest();
container.Register(c =>new OAuthTokenManager(c.ResolveNamed<IBuilderFactory>("OAuthTokenBuilderFactory"))).As<IOAuthTokenManager>().InstancePerApiRequest();
This can be solved using AutoFac's support for object graph lifetime scoping.
Cache the current SqlServerConnectionContext in an object scoped to the lifetime of your controller.
Within the SqlServerConnectionContext factory type, once the connection is created assign it to the backing field of the current lifetime-scoped cache
Any types scoped within the lifetimes scope of a controller can then access the connection associated with that controller through the cache
The only complexities I can think of are:
If the controller is not actually the root of a lifetime scope for all types with a dependency on a specific connection. I.e. if they fall outside the lifetime of the controller.
If any of the dependencies are registered as single instance. In which case they will not be able to resolve the Cache as it is currently implemented as it is PerApiRequest.
For example:
public interface ISqlServerConnectionContextCache
{
ISqlServerConnectionContext CurrentContext { get; set; }
}
public class SqlServerConnectionContextScopeCache : ISqlServerConnectionContextCache
{
public ISqlServerConnectionContext CurrentContext { get; set; }
}
public interface ISqlServerConnectionContextFactory
{
ISqlServerConnectionContext Create();
}
// The factory has the cache as a dependancy
// This will be the first use of the cache and hence
// AutoFac will create a new one at the scope of the controller
public class SqlServerConnectionContextFactory : ISqlServerConnectionContextFactory
{
private string _connectionString;
private ISqlServerConnectionContextCache _connectionCache;
public SqlServerConnectionContextFactory(ISqlServerConnectionContextCache connectionCache,
string connectionString)
{
_connectionCache = connectionCache;
_connectionString = connectionString;
}
public ISqlServerConnectionContext Create()
{
var connectionContext = new SqlServerConnectionContext(_connectionString);
connectionContext.Open();
_sqlServerConnectionContextProvider.CurrentContext = connectionContext;
return connectionContext;
}
}
public class MyController : ApiController
{
private ISqlServerConnectionContext _sqlServerConnectionContext;
public MyController(Func<string, ISqlServerConnectionContextFactory> connectionFactory)
{
_sqlServerConnectionContext = connectionFactory("MyConnectionString");
}
}
// As the cache is lifetime scoped it will receive the single instance
// of the cache associated with the current lifetime scope
// Assuming we are within the scope of the controller this will receive
// the cache that was initiated by the factory
public class MyTypeScopedByController
{
public MyTypeScopedByController(ISqlServerConnectionContextCache connectionCache)
{
var sqlServerConnectionContext = connectionCache.CurrentContext;
}
}
// AutoFac wiring
builder.RegisterType<SqlServerConnectionContextScopeCache>()
.As<ISqlServerConnectionContextCache>()
.InstancePerApiRequest();
builder.RegisterType<SqlServerConnectionContextFactory>()
.As<ISqlServerConnectionContextFactory>()
.InstancePerDependency();

Data Access Layer design : Different providers same tables and singleton

I need to build a Data Access Library to be used from many small applications afterwards.
It will heavily use the DataReader objects. The tables may exist with same structure either in SQL Servers or in DB2/400. This means that a method for example
GetItemsByWarehouse()
Must be able to run either against SQL Server DB or DB2. Where it will run depends on the server availability and user selection.
What i plan to do (and need advice on it) is :
Implement the DAL based on Singleton design Pattern to ensure that i will have only one instance of my Library.
Have a property that will set the connection string.
Have a property that will set if the target server is AS400 or SQL.
I dont know if this course of action is correct. Should i implement point #3 or i could get the type from the connection string?
Also How i should implement such a method as above? check the property and decide inside the method if i will use Sqlconnection or OleDbConnection e.t.c?
I paste this code from my micro Orm . There are multiple overloads for the constructor to specify what Db you want used.
public class DbAccess : IDisposable
{
public DbAccess()
{
var cnx=ConfigurationManager.ConnectionStrings[0];
if (cnx==null) throw new InvalidOperationException("I need a connection!!!");
Init(cnx.ConnectionString,ProviderFactory.GetProviderByName(cnx.ProviderName));
}
public DbAccess(string connectionStringName)
{
var cnx = ConfigurationManager.ConnectionStrings[connectionStringName];
if (cnx == null) throw new InvalidOperationException("I need a connection!!!");
Init(cnx.ConnectionString, ProviderFactory.GetProviderByName(cnx.ProviderName));
}
public DbAccess(string cnxString,string provider)
{
Init(cnxString,ProviderFactory.GetProviderByName(provider));
}
public DbAccess(string cnxString,DBType provider)
{
Init(cnxString,ProviderFactory.GetProvider(provider));
}
public DbAccess(string cnxString,IHaveDbProvider provider)
{
Init(cnxString, provider);
} //other stuff
}
Note that the DAO (DbAccess) doesn't care about the concrete provider.
Here's how the ProviderFactory looks. Here you can add a method to detect the db and to return a provider.
internal static class ProviderFactory
{
public static IHaveDbProvider GetProviderByName(string providerName)
{
switch (providerName)
{
case SqlServerProvider.ProviderName:return new SqlServerProvider();
case MySqlProvider.ProviderName:return new MySqlProvider();
case PostgresProvider.ProviderName:return new PostgresProvider();
case OracleProvider.ProviderName:return new OracleProvider();
case SqlServerCEProvider.ProviderName:return new SqlServerCEProvider();
case SqliteProvider.ProviderName:return new SqliteProvider();
}
throw new Exception("Unkown provider");
}
public static IHaveDbProvider GetProvider(DBType type)
{
switch (type)
{
case DBType.SqlServer: return new SqlServerProvider();
case DBType.SqlServerCE: return new SqlServerCEProvider();
case DBType.MySql: return new MySqlProvider();
case DBType.PostgreSQL:return new PostgresProvider();
case DBType.Oracle:return new OracleProvider();
case DBType.SQLite:return new SqliteProvider();
}
throw new Exception("Unkown provider");
}
}
For more code snippets and inspiration you can check the Github repo
I would advice against the Singleton pattern, it's much better to let a DI container to manage the instance life. Also, the app should use the interface of the DAO not the concrete instance (this will help you in the future).
Take a look at Abstract Factory Pattern
You can have an interface with the DAL contracts and an implementations for each context. Using a Factory it can decide which implementation will use in each case. The factory will need the "switch rule" to decide what to use.

Categories