We have an ASP.NET REST service implemented with Nancy (and TinyIoc), which interfaces with a quite large legacy application. We would like to transition to full dependency injection. At the moment most of our modules instantiate the controllers directly, and takes a context class which holds the request information using the NancyContext Context property. Something like this:
public FooModule(ILegacyService legacyService) {
Get["/"] = parameters => new FooController(new RequestContext(Context), legacyService).GetFoo();
}
We would like to inject the controllers directly in the module, and get everything handled by the super-duper-happy-path :)
Our problems all stem from the fact that we need information from NancyContext. The url, headers etc. So we have attempted various approaches to get to dependency injection nirvana.
Attempting to inject controllers failed, since they're instantiated in application scope, and so any dependency to RequestContext would not have the current context information. Even registering RequestContext in ConfigureRequestContainer did not ripple through to all dependants, and they would hold references to an out of date RequestContext.
We have tried to property inject the context using IRequestStartup, and this seemed successful, until we ran into concurrency issues. Simultaneous requests in different threads would overwrite the application scope RequestContext.
We found out that we could call container.AutoRegister() in ConfigureRequestContainer, but this resulted in severe lag, since registrations takes seconds with the amount of types we have.
Using AsPerRequestSingleton() in ConfigureApplicationContainer seems like it will register once, and then instantiate per request, but there doesn't seem to be a way to get auto registration to adhere to this.
It seems like we need to register all types manually, and keep this configuration up to date manually. Is this the case? We really would prefer to have some type of auto registration with per request lifetime.
I have created a small test project (https://github.com/Rassi/NancyIocTest) in which I attempted some of these solutions.
Using DefaultNancyAspNetBootstrapper you can create your own auto registering like this:
public class Bootstrapper : DefaultNancyAspNetBootstrapper
{
protected override void ConfigureApplicationContainer(TinyIoCContainer container)
{
var assemblyClasses = Assembly.GetExecutingAssembly().GetTypes().Where(type => type.IsClass);
foreach (var assemblyClass in assemblyClasses)
{
var interfaces = assemblyClass.GetInterfaces();
if (interfaces.Count() == 1)
{
container.Register(interfaces[0], assemblyClass).AsPerRequestSingleton();
}
}
}
Everything is then instantiated per request, and you can inject context information using RequestStartup():
protected override void RequestStartup(TinyIoCContainer container, IPipelines pipelines, NancyContext context)
{
base.RequestStartup(container, pipelines, context);
var requestUrl = container.Resolve<IRequestUrl>();
requestUrl.Context = context;
}
}
This is a simple proof of concept, which will find classes which implement one interface, and register it to that. A couple of issues should probably be handled, such as: Registering classes implementing multiple interfaces (perhaps using the convention of registering Name to IName). And also handling multiple classes registering the same interface.
Related
How to replicate this code with Autofac syntax?
public static class MenuConfig
{
public static void Initialize()
{
var _menuService = DependecyFactory.GetInstance<IMenuService>();
Parameters.Menu = _menuService.Menu();
}
}
Before calling this a "duplicate question" please note that I'm looking for an Autofac command. I CANNOT inject the interface anywhere and then call "Resolve". What I need to is perform an "InstancePerRequest" inline and uninjected so I don't have to do this:
var _service = new Service(new Dependency(new context()));
LightInject has a method that allows instantiation from an interface OUTSIDE of a constructor like this:
var _service = DependecyFactory.GetInstance<IService>();
What is the equivalent method for Autofac?
When calling containerBuilder.Build() you get back a container which implements IContainer and ILifetimeScope, whenever you get hold of one of these interfaces, you can resolve types from it:
container.Resolve<IService>();
If you want this container to be static, you could add the container as a static property to the Program or Startup class (depending if you're creating a Console or ASP.NET application).
Remember that the root container will be around for the entire duration of your application, so this can result in unwanted memory leaks when used incorrectly. Also see the warning in the documentation.
Still, it's perfectly possible to do the memory management yourself by resolving an Owned<> version from your interface:
using (var service = Program.Container.Resolve<Owned<IService>>())
{
service.Value.UseService();
}
Anyway, since you mention a static class in the comments, the best solution is to change that into a non-static class and register it as a singleton with Autofac. Then you can inject a Func<Owned<IService>> serviceFactory into that singleton and create/dispose an instance of the service wherever you need it.
using (var service = serviceFactory())
{
service.Value.UseService();
}
This is simply not possible with Autofac. All other solutions involving Autofac will require code refactoring which may potentially break software functionality. So unfortunately, the most elegant and least disruptive solution is this:
var _service = new Service(new Dependency(new context()));
Since this is an edge case addressing only one part of the software, this compromise is acceptable. It would be nice, however, if Autofac implemented this functionality in some future release.
I have an application that creates a lifetime scope at some point like so:
public class Main
{
public void Main()
{
using (ILifetimeScope scope = AutofacContainer.Container.BeginLifetimeScope())
{
scope.Resolve<SomeClass>();
}
}
}
Within SomeClass I have logic which then calls a lot of different classes and so on..
Then, about 10 methods down the call stack I need to use the main scope to do this:
public class ActivatorFactory : IActivatorFactory
{
public T Create<T>(Type instance)
{
using (ILifetimeScope scope = AutofacContainer.Container.BeginLifetimeScope())
{
return (T)scope.Resolve(instance);
}
}
}
The problem with that is that now I've created a new scope which is just used to resolve a runtime type. I want to be able to use the main scope to resolve this type. How can I do so without passing the main scope down to this factory class through 10 different methods/functions?
The only "hacky" solution I thought of is to just have a static property on my ActivatorFactory and set the scope in my Main class like so:
public class Main
{
public void Main()
{
using (ILifetimeScope scope = AutofacContainer.Container.BeginLifetimeScope())
{
ActivatorFactory.Scope = scope;
scope.Resolve<SomeClass>();
}
}
}
Is there a cleaner solution to use the main scope in another part of my application?
I had this need for a CancellationTokenSource instance per lifetime scope, where children are linked to their parent. If the the root scope's CancellationTokenSource, is canceled, all children lifetime scope's CancellationToken are canceled. To accomplish this, I created:
private sealed class ParentLifetimeScopeAccessor
{
private readonly ILifetimeScope _lifetimeScope;
public ParentLifetimeScopeAccessor(ILifetimeScope lifetimeScope)
{
_lifetimeScope = lifetimeScope;
_lifetimeScope.ChildLifetimeScopeBeginning += OnChildLifetimeScopeBeginning;
}
public ILifetimeScope ParentLifetimeScope { get; private set; }
private void OnChildLifetimeScopeBeginning(object sender, LifetimeScopeBeginningEventArgs e) =>
e.LifetimeScope.Resolve<ParentLifetimeScopeAccessor>().ParentLifetimeScope = _lifetimeScope;
}
With a registration, you can now access your parent's scope:
builder.RegisterType<ParentLifetimeScopeAccessor>().InstancePerLifetimeScope();
With the parent lifetime scope accessor, linked CancellationTokenSource instances can be created:
private static CancellationTokenSource CancellationTokenSourceFactory(IComponentContext context)
{
var scopeAccessor = context.Resolve<ParentLifetimeScopeAccessor>();
var parentScope = scopeAccessor.ParentLifetimeScope;
return null == parentScope
? new CancellationTokenSource()
: CancellationTokenSource.CreateLinkedTokenSource(parentScope.Resolve<CancellationTokenSource>().Token);
}
CancellationToken resolver:
private static CancellationToken CancellationTokenResolver(IComponentContext context) =>
context.Resolve<CancellationTokenSource>().Token;
Two registrations:
builder.Register(CancellationTokenSourceFactory).AsSelf().InstancePerLifetimeScope();
builder.Register(CancellationTokenResolver).AsSelf().InstancePerDependency();
If you're not using ActivatorFactory for your app (and you shouldn't be if you're using inversion of control) then delete it and think about what you're trying to test.
Are you trying to test that you can generally just resolve things from Autofac? Autofac has a raft of unit tests as well as millions of successful users. No value in testing the framework.
Are you trying to test that you registered all the things you needed to register? There's not a lot of value in that, either, for a couple of reasons: first, you'll hit that at runtime pretty quickly and see it in those tests; second, in a large, decoupled system those tests get really stale really quickly. It's a maintenance hassle.
Are you trying to test that a specific object graph can be composed based on your registrations? I might buy this one. See below.
Let's say it's the last thing - you have a really complex and troublesome object graph you want to ensure you can create because people keep breaking it. I could see that.
Separate your registrations out into an Autofac module. Use the Autofac module to test.
public class MyRegistrations : Autofac.Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<Thing>();
// and all your other registrations.
}
}
then in the unit test
var builder = new ContainerBuilder();
builder.RegisterModule<MyRegistrations>();
var container = builder.Build();
var thing = container.Resolve<Thing>();
// Assert on the resolved thing.
You can use that same module to encapsulate your registrations in the app and then you'll actually be testing the complex registration but without a factory you're not using.
Warning: It is a slippery slope between testing some complex registration and testing all registrations. Like I said, you really don't want to test every registration you have. I've fallen down this slope. It's a maintenance nightmare. Add a registration to the module/app, add a test. Uh oh, we refactored, now the registrations are all different. Ugh. That's less testing about behavior than about characterization (not "what do I want it to do" but "what does it do now"). Pain. Suffering.
If you are using ActivatorFactory in your app for, say, service location instead of using some more standard thing like CommonServiceLocator that already does that for you and for which Autofac already directly integrates... then just test ActivatorFactory with a real container but with some arbitrary test registrations rather than the whole set from the real app. The functionality of ActivatorFactory doesn't have any bearing on what's registered inside it.
And, yeah, if you're using ActivatorFactory and need to keep it around, you'll have to hand it an ILifetimeScope at app startup. That's how service locators work. You'll see that all over in the Autofac docs when you look at how to integrate with apps like ASP.NET, WCF, and others.
I am trying to set up my AutoFac registration in such a way that this test passes:
[Test]
public void Autofac_registration_test()
{
// Given
var builder = new ContainerBuilder();
RegisterServices(builder);
var container = builder.Build();
// When
var firstHub = container.Resolve<Hub>();
var secondHub = container.Resolve<Hub>();
// Then
firstHub.Should().NotBe(secondHub);
firstHub.FooRepo.Context.Should().Be(firstHub.BarRepo.Context);
firstHub.FooRepo.Context.Should().NotBe(secondHub.FooRepo.Context);
}
i.e. I want to use the same Context object all the way down within a single Hub, but use a different one when a new Hub is created.
RegisterServices is currently just:
private void RegisterServices(ContainerBuilder builder)
{
builder.RegisterType<MyHub>();
builder.RegisterType<FooRepo>();
builder.RegisterType<BarRepo>();
builder.RegisterType<Context>(); // How should I scope this?
}
Which fails at firstHub.FooRepo.Context.Should().Be(firstHub.BarRepo.Context); because Context is transiently scoped.
But scoping context per lifetime also fails, this time at firstHub.FooRepo.Context.Should().NotBe(secondHub.FooRepo.Context);.
It feels like this is a reasonable thing to want to do, so am I missing anything obvious out-of-the-box here?
Or will I have to do something manual to track Hub creation?
(For context, this is for a SignalR app. Hubs are created per SignalR request, so this was an attempt to match the unit-of-work lifetime of an HTTP request in normal webby situations).
What #Steven said in his comment was correct, I needed a per-object-graph lifestyle.
Castle.Windsor supports this, so I swicthed to using that for my dependency injection instead of AutoFac. The registration now looks like:
container.Register(Component.For<Hub>().LifestyleTransient());
container.Register(Component.For<FooRepo>().LifestyleTransient());
container.Register(Component.For<BarRepo>().LifestyleTransient());
container.Register(Component.For<Context>().LifestyleBoundTo<Hub>()); // Important bit
For more information, see: http://docs.castleproject.org/Windsor.LifeStyles.ashx?HL=scope#Bound_8
I'm new to AutoFac and am currently using custom modules inside my app config to boot up some core F# systems. The code I'm using is
var builder = new ContainerBuilder();
builder.RegisterType<DefaultLogger>().As<IDefaultLogger>();
builder.RegisterModule(new ConfigurationSettingsReader("autofac"));
builder.Build();
And inside my app config I have the appropriate logic to start up the relevant systems. I would like to have access to the DefaultLogger inside my Modules. Metadata for the Module base class has the following options available to me:
protected virtual void AttachToComponentRegistration(IComponentRegistry componentRegistry, IComponentRegistration registration);
protected virtual void AttachToRegistrationSource(IComponentRegistry componentRegistry, IRegistrationSource registrationSource);
public void Configure(IComponentRegistry componentRegistry);
protected virtual void Load(ContainerBuilder builder);
I've only been using Load so far and I can't see any methods on the builder that would allow me to get at the logging service.
When registering something within your modules with autofac instead of using RegisterType method you might use Register method:
builder.Register(c =>
{
IComponentContext ctx = c.Resolve<IComponentContext();
IDefaultLogger logger = ctx.Resolve<IDefaultLogger>();
...do something with logger...
return ...return object you want to register...;
});
The answer turned out to be incredibly simple. I just added IComponentContext as a dependency to my Module's implementation
public class LocalActorSystemModule : Module {
private IComponentContext m_ComponentContext; // A service for resolving dependencies required by this module
public LocalActorSystemModule(IComponentContext componentContext) {
m_ComponentContext = componentContext;
}
And let AutoFac inject the IComponentContext for me. That way I can resolve any dependencies I require inside the module.
Rule of thumb for using every IoC/DI Container: Resolve once! => then you get all dependencies resolved for your requested object. If you try to resolve multiple times, register other objects (in the meantime) you're stuck in hell. Really. If you want to retrieve objects for different purposes at different places and time points (resolved from central registration) you may be looking for the Service Locator Pattern instead (but this is often described as an Anti-Pattern, too).
Modules have the purpose to bundle related registrations (conditionally) as statet in the Autofac documentation:
A module is a small class that can be used to bundle up a set of
related components behind a ‘facade’ to simplify configuration and
deployment.
... so if they are just a sum of registrations and the container has not yet been build you are not able to resolve and use an (even previously registered) component immediately (except calling a method on the registrant itself through OnActivate* hooks or when using instance registration, but I think this is not the case for your example). The components are just in the state of registration but the complete context is not ready for resolving. What would happen if you override the registration in another Module? Then you would have injected different objects... bad idea. Maybe you should rethink your application design and which objects have which responsibilities.
By the way: Logging is a cross cutting concern that is often "injected / resolved" by calling a separate static factory or service instead of doing constructor / property injection (see usage of Common.Logging for example).
public class MyModule : Module
{
private static readonly ILog Log = LogManager.GetLogger<MyModule>();
protected override void Load(ContainerBuilder builder)
{
Log.Debug(msg => msg("Hello")); // log whatever you want here
}
}
You can also try to use AOP libraries and weave the dependency into the Module (using reflection). But I don't think it's worth to try just for logging in a Module.
Anyway: #mr100 has already shown the right usage during registration. There you can also handle activation etc. but not do logging for the Module itself.
In Microsoft Unity IoC, if I call Resolve<SomeType>(), can I guarantee that the object returned is the one that was created during the current session?
For example, three users sign on, and let's say that the object of SomeType that gets created in the container has different values for each user. Will a call to Resolve return the object that was created for the current user? Or would it do something stupid like return the last one that was created?
I'm having troubles testing this myself due to some environment problems and I need to check something in soon, so if someone could answer this it would be very helpful!
Edit
Forgive me for I am very new to Unity, but based on what I read here, it seems like I should be able to register objects in the container with a unique name and retrieve them by that name. So, wouldn't I be able to use a session ID or some other value that persists within a session to retrieve my object?
Oh wow, lifetime management using Unity in am MVC app. Where do I start?
First of all, session singletons are not really possible as there is no ASP.NET system that will guarantee that the same instance will be used between requests in the same session. The session can mimic the same object persisted within the session by serializing and deserializing it between requests.
Transient instances - i.e. simple registrations without lifetime management specification are sufficient 99% of the time. This implies that an instance of registered type will be created every time it is needed.
It is very rarely that you need instances to live throughout the lifetime of the request. However when you need those, you really need those. A connection to a DB is a perfect candidate for this. Request singletons, on the other hand are much easier to create and manage.
The most elegant solution is to use Unity's child container feature. A child container can be created at the beginning of the request, disposed at the end of the request (as an added bonus it will dispose all ContainerControlledLifetimeManager instances).
When creating a child container, all registrations are still available from the parent container, so you need to register request specific stuff with the child container.
Here is pseudo-code to get this working:
private void Application_Start() {
_parentContainer = new UnityContainer();
//creates a transient registration, available at any point in the app.
_parentContainer.RegisterType<IParentIntf, ParentIntfImpl>();
ControllerBuilder.Current.SetControllerFactory(new ServiceLocatorControllerFactory());
}
private void Application_BeginRequest() {
var childContainer = _parentContainer.CreateChildContainer();
//registers a request "singleton"
//This registration is a type registration, an instance of RequestInterfaceImpl
//will be created when needed and then kept in the container for later use.
childContainer.RegisterType<IRequestInterface,RequestInterfaceImpl>(new ContainerControlledLifetimeManager());
//save the child container in the context, so we can use it later
HttpContext.Items["childContainer"] = childContainer;
}
private void Application_EndRequest() {
//dispose the child container
((IUnityContainer)HttpContext.Items["childContainer"]).Dispose();
}
One other thing that needs to be done is to override the Controller Factory to use the child container to create controllers. Controller are the first point of entry into the application and they could simply take a dependency on other components in their constructor.
public class UnityControllerFactory : DefaultControllerFactory {
#region IControllerFactory Members
public override IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName) {
IController controller;
controllerName = controllerName.ToLower();
var container = ((IUnityContainer)HttpContext.Items["childContainer"])
if(container.IsRegistered<IController>(controllerName))
controller = container.Resolve<IController>(controllerName);
else
controller = base.CreateController(requestContext, controllerName) ;
return controller;
}
}
The default behaviour will be to return a new instance for each resolve call, this isn't what you want.
It would be possible to create and resolve the same instance within a session, but there is no built in support as far as I know. You would have to write your own lifetime manager, and then use this when registering your type.
There is a lifetime manager that can do per thread instances, but this isn't useful for sessions as threads will get re-used, and resolve would need to also work across multiple requests to be truly session-scoped.
It's entirely possible that someone has written a lifetime manager for this.