zcz527 / autofac

Automatically exported from code.google.com/p/autofac
Other
0 stars 0 forks source link

Cannot access a disposed object. #299

Closed GoogleCodeExporter closed 8 years ago

GoogleCodeExporter commented 8 years ago
Latest version of Autofac 2.4.4 introduced a breaking change in Disposed 
containers behavior. While I understand the reasons behind it, it broke my code 
and now I'm wondering how can I do the same scenario without polluting the main 
container.

class LazyClass
{
    public void DoSomething() { }
}

class SomeClass
{
    public event EventHandler WatchOut = (s, ea) => { };
    public void Start()
    {
        WatchOut(this, EventArgs.Empty);
    }
}

class LazyInterceptor
{
    Lazy<LazyClass> lazy;
    public LazyInterceptor(Lazy<LazyClass> lazy)
    {
        this.lazy = lazy;
    }
    public void Register(SomeClass some)
    {
        some.WatchOut += (s, ea) => lazy.Value.DoSomething();
    }
}

[TestMethod]
public void LazyAndEvents()
{
    var builder = new ContainerBuilder();
    builder.RegisterType<LazyClass>().SingleInstance();
    var container = builder.Build();

    var someClass = new SomeClass();

    using (var inner = container.BeginLifetimeScope(cb =>
    {
        cb.RegisterType<LazyInterceptor>().SingleInstance();
    }))
    {
        var interceptor = inner.Resolve<LazyInterceptor>();
        interceptor.Register(someClass);
    }

    someClass.Start();
}

Original issue reported on code.google.com by rikard.p...@gmail.com on 22 Feb 2011 at 5:22

GoogleCodeExporter commented 8 years ago
Thanks for getting in touch. This issue tracker is for bug reports and 
enhancement requests only - please post your question to Stack Overflow with 
the 'autofac' tag, we will make every effort to get you on the right track. 
Cheers!

Original comment by nicholas...@gmail.com on 23 Feb 2011 at 10:02

GoogleCodeExporter commented 8 years ago
I know it's for bug reports. I guess I should explain myself better ;)

I think it's a bug that Autofac thinks I'm resolving component from disposed 
container. LazyClass is not registered in inner scope, but in main container 
and it shouldn't matter when it was created. 
Lazy resolve behavior seems to me like a bug and that's why I reported this.

I know that I could use Owned<Lazy<LazyClass>> as argument and then it will 
work as before, but:
1) I don't like Owned (it takes dependency on Autofac)
2) still think it's a bug

I'm attaching new Lazy resolver which behaves as Owned resolver.

What I would like is that lazy respects context of it's service, but that's not 
the same as in this patch.

Original comment by rikard.p...@gmail.com on 5 Apr 2011 at 1:38

Attachments:

GoogleCodeExporter commented 8 years ago
Hi Rikard,

Sorry about the terse reply previously - always rushing rushing ;)

Thanks for following up, I had a look at the patch and have more of an idea 
what you're expecting. In the way it is implemented you'll 'leak' the nested 
scope that is created.

I see what you mean about the `Lazy` implementation working independently of 
scope, but I'm afraid this might not be possible in the model Autofac uses. 
Although the underlying value is a single shared instance, any number of 
different `Lazy` instances might exist on top of it - the `Lazy` adapter is 
specific to the component that resolves it.

A workaround you could try is to register the `Lazy` instance manually as 
`SingleInstance()`, overriding the default one that Autofac provides. This 
would probably be more straightforward than modifying the adapter itself.

In your example, you're explicitly (through `using`) ending the lifetime of 
`LazyInterceptor` before calling `someClass.Start()` - I don't think there's a 
good way to get a predictable result out of this without keeping the lifetime 
of the nested scope open for the duration of the use of the components in it.

I'm guessing that your real application scenario is somewhat more complicated, 
so I can't offer much in the way of alternative suggestions. One question to 
consider might be why the interceptor is being created in a nested scope to 
start with?

Regarding the role of `Owned`, as with all relationship types they are best as 
building blocks for other infrastructure. If you take a dependency on, or use 
`Owned<T>`, consider doing it from an infrastructure class that sits alongside 
your Autofac-specific registration code, but exposes Autofac-independent 
interfaces back to the application.

Hope this helps,
Nick

Original comment by nicholas...@gmail.com on 5 Apr 2011 at 10:13

GoogleCodeExporter commented 8 years ago
I wasn't pleased with behavior of that patch too.

I thought about it some more and I have a better solution to my problem.
My issue in all this is CheckNotDisposed() in ResolveComponent.

If that line is replaced with something similar to this
if (IsDisposed)
   return _parent.ResolveComponent(registration, parameters);

my problem goes away and container behaves the way I expect it to.

When I think about what Dispose means for containers, those two lines expresses 
better what it means: the container will not be able to resolve anything 
registered in it anymore -> it will just pass request to it's parent.

As for other stuff:
I like Owned as relationship idea, but can't use it, because most of the 
infrastructure is ignorant of Autofac.
Test case is very similar to my scenario:
set up the interceptors on some infrastructure objects for AOPing on them.
Use Lazy so that proxies can be set up after scan.

Why am I doing it in nested container?
To reduce the amount of registrations in main container.
This stuff shouldn't be resolvable after setup.
While I could let the container live (not dispose it after scan and setup) I 
have no further use for it, so that solution would be just workaround for 
current Autofac behavior.

Thanks,
Rikard

Original comment by rikard.p...@gmail.com on 6 Apr 2011 at 9:03

GoogleCodeExporter commented 8 years ago
I asked this question on 
http://stackoverflow.com/questions/7782838/how-should-container-behave-when-it-i
s-disposed

Maybe you can share your thought's.

Original comment by rikard.p...@gmail.com on 16 Oct 2011 at 6:53