Reputation:
I'm having hard time integrating autofac in my applcation..
My application integrates with other applications, when a connection to another application is made its being maintained by a fitting "Protocol" object
// This class is inherited by a few other classes
public abstract class Protocol
I have a layer that is run by it's own thread and handles connection requests. For each kind of request a different kind of protocol is created (a different protocol object)
// For example lets say every protocol (Inhertiance of Protocol abstract object)
// takes in ctor these 3 services + runtime configuration object:
public Protocol1(IFramingAgent, IFramingAlgorithm, IFramingParser, configObject configuration)
My protocol objects are keyed registered as Protocol. Also, Each service is registered with key because each protocol uses a different kind that inherits from the same interface. Of course, all of these are registered as PerDependency (although I don't really understand the difference between this lifeCycle against PerScope, would really appreciate an explanation)
And here is my terrible class:
public class ProtocolsLayer : Layer
{
private IFrameworkDependencyResolver _resolver;
private IConfigurationService _configService;
public ProtocolsLayer(IFrameworkDependencyResolver resolver, IConfigurationService configurationService)
{
_resolver = resolver;
_configService = configurationService;
}
void HandleConnection1()
{
// What I have at the moment (terrible):
// Resolve the fitting services (All keyed - key is received by the type, Resolve and ResolveWithParameters used here are my wrappers)
var agent = _resolver.Resolve<IFramingAgent>(typeof(Protocol1FramingAgent));
var algo = _resolver.Resolve<IFramingAlgorithm>(typeof(Protocol1FramingAlgorith));
var parser = _resolver.Resolve<IFramingParser>(typeof(Protocol1FramingParser));
// A parameter I get and pass to each protocol at runtime
var protocolConfig = _configService.GetConfig<Protocol1Configuration>();
// Finally resolve the protocol with it's parameters:
protocol = _resolver.ResolveWithParameters<IProtocol>(typeof(Protocol1), new List<object>{
agent, resolver, parser, protocolConfig
});
//...
// Theres gotta be a better way!!
}
void HandleConntection2()
{
// Same as in protocol1
}
void HandleConnection3()
{
// Same as in protocol1
}
}
Take in mind that I don't want references to autofac, meaning I can't use IIndex<> which I heard off.
Thanks!
Upvotes: 2
Views: 378
Reputation: 16187
You should let the dependency injection framework manage instanciation.
You use a ResolveWithParameter
method where these parameters has been resolved by the dependency injection framework. It is not required and you can let the framework find the dependency for you :
If Protocol1
needs a named parameter you can specify it during registration process.
builder.Register(c => c.Resolve<IConfigurationService>()
.GetConfig<Protocol1Configuration>())
.As<Protocol1Configuration>();
builder.RegisterType<Protocol1>()
.Named<IProtocol1>(nameof(Protocol1))
.WithParameter((pi, c) => pi.ParameterType == typeof(IFramingAgent),
(pi, c) => c.ResolveNamed<IFramingAgent>(nameof(Protocol1))
.WithParameter((pi, c) => pi.ParameterType == typeof(IFramingAlgorithm),
(pi, c) => c.ResolveNamed<IFramingAlgorithm>(nameof(Protocol1));
builder.RegisterType<FramingAgentProtocol1>()
.Named<IFramingAgent>(nameof(Protocol1));
builder.RegisterType<FramingAlgorithmProtocol1>()
.Named<IFramingAlgorithm>(nameof(Protocol1));
Then ProtocolsLayer
only need dependency on IIndex<String, Func<IProtocol>>
(or Func<Owned<Protocol1>>
)
public class ProtocolsLayer
{
public ProtocolsLayer(IIndex<String, Func<IProtocol>> index)
{
this._index = index;
}
private readonly IIndex<String, Func<IProtocol>> _index;
public void HandleConnection1()
{
IProtocol protocol = this._index[nameof(Protocol1)]();
}
}
If you don't want to introduce dependency on IIndex<,>
for your whole application you can introduce a IProtocolFactory
that will be defined in your runtime and create the implementation only for the registration project.
In your runtime project :
public interface IProtocolFactory
{
IProtocol Create(String protocolName)
}
In your registration project :
public class ProtocolFactory : IProtocolFactory
{
public ProtocolFactory(IIndex<String, IProtocol> index)
{
this._index = index;
}
private readonly IIndex<String, IProtocol> _index;
public IProtocol Create(String protocolName)
{
return this._index[typeof(TProtocol).Name];
}
}
Then you ProtocolsLayer
class will look like this :
public class ProtocolsLayer
{
public ProtocolsLayer(IProtocolFactory protocolFactory)
{
this._protocolFactory = protocolFactory;
}
private readonly IProtocolFactory _protocolFactory;
public void HandleConnection1()
{
IProtocol protocol = this._protocolFactory.Create("Protocol1");
}
}
You can also register a Func<String, IProtocol>
which will named resolve IProtocol
ProtocolsLayer
will look like this :
public class ProtocolsLayer
{
public ProtocolsLayer(Func<String, IProtocol> protocolFactory)
{
this._protocolFactory = protocolFactory;
}
private readonly Func<String, IProtocol> _protocolFactory;
public void HandleConnection1()
{
IProtocol protocol = this._protocolFactory("Protocol1");
}
}
and the registration like this :
builder.Register(c => (String namedProtocol) => c.ResolveNamed<IProtocol>(namedProtocol)
.As<Func<String, IProtocol>>();
But I won't recommend this solution because the intent of Func<String, IProtocol> protocolFactory
dependency is not clear. Having a IProtocolFactory
interface makes dependency goal easy to understand.
Upvotes: 1