The Scope being disposed is not the Ambient Scope ...
# help-with-umbraco
o
Hi all, I have a repository pattern set up for some custom database tables, here's the Update method:
Copy code
csharp
public virtual async Task<TOut> Update(TOut item)
{
  using var scope = _scopeProvider.CreateScope();
  using (var transaction = scope.Database.GetTransaction())
  {
    var poco = _mapper.Map<T>(item);
    await scope.Database.UpdateAsync(poco);
    transaction.Complete();
    item = _mapper.Map<TOut>(poco);
  }
  scope.Complete();
  return item;
}
The above class is registered as transient. If I call this method multiple times in one request (e.g. in a foreach loop), then I seem to run into this exception:
The Scope being disposed {guid} is not the Ambient Scope {guid}
and all subsequent attempts to run the method result in
No AmbientContext was found.
exceptions; only a restart fixes it until it happens again. The addition of a
Thread.Sleep(500);
to the start of the Update method seems to completely fix the issue. But that's a gross band aid fix which only masks whatever the underlying issue is. (feels like the first scope is not being closed in time and the second scope is created as a child scope?) has anyone ran into this before? Am I missing something stupidly obvious?
h
I had a similar issue but it was due to a nested call, to get around it I had to declare them as autocomplete in the constructor and then just do a transaction complete, don't know if that will help
o
Cheers Huw, I'll have a go at using the autocomplete option tomorrow 🙂
a
Hi @Owain Jones , you ever managed to fix this ? Think Im running into something similar
o
Unfortunately no, I never found a solution, I'm still using the awful
Thread.Sleep(500);
workaround...
a
Ouf..
I have a viewcomponent that does a database call to access a custom table, and the ViewComponent is displayed 3x on the same page which causes an error in
Copy code
public IEnumerable<T> Where(Expression<Func<T, bool>> where)
    {
        using var scope = _scopeProvider.CreateScope(autoComplete: true);
        var sql = scope.SqlContext.Sql()
            .Select<T>()
            .From<T>()
            .Where(where);

        return scope.Database.Fetch<T>(sql).ToList();
    }
So I think its fairly similar
But it's only on boot up for me.. Subsequent calls are good
As a workaround, I added runtime caching on it, and if its not in the cache, it sleeps for 500ms and THEN gets the items..:-)
Ugly, but works 😭
o
Nice, that sounds like a good workaround! It really is a frustrating issue, and I'm honestly surprised not more people have ran into it... I've been meaning to try and create a reproducible example of the issue, on a vanilla install, so I can properly raise an issue on the umbraco github repo. I really need to do that soon 😬
a
Well after restarting 10x, it's back, not as consistent as before, but it is still there
But definitly seems like theres an underlaying problem
o
Yea it never seemed too consistent to me either, sometimes it would work, sometimes not... To me it occurred more often when doing an insert/update on an object that updated multiple rows. It definitely seems linked to how "fast" the system can seem to dispose of the old scope in the background, before we try to create a new one. But why it creates the new one as a child of the first, I'm not sure, unfortunately this is where my knowledge of this area falls short...
a
Yea same here 😦
s
This seems like an interesting issue. If you can find a way to trigger this reliably, worst case with a k6 test i guess, we can have a proper look at it. On side note. Why are you registering a repository as a transient instead of a scoped dependency? A repo should have no internal data so no need to make it transient as there is no risk of logic contaminating it's state.
a
You're absolutely right.. damn.. Switching to AddScoped fixed it it seems!
I am however curious how you knew that we(I atleast) were using transient instead of scoped, dont see that anywhere in the text 😄
o
Huh, I have no idea, it was like that when I inherited the repo code from a colleague, I'll swap to over to Scoped and report back 🙂
s
I knew owain was because of the text under his code example
a
Bloody.. Totally overlooked it, scanned 3x , but I also had it transient...
Hah
Thanks Sven!
s
Glad i could help 🙂
o
Apologies, this took longer than expected, unfortunately I don't think I can change my repos to Scoped; as they are being used in some singleton classes too. (injected into classes in a DI Collection using OrderedCollectionBuilderBase stuff) Also, just so I understand, why could the fact that the repos are transients cause this issue?
d
My repositories are usually singletons, so you could go for that, alternatively, you can inject the
IServiceScopeFactory
to create a service scope and consume scoped services from that.
s
I do not fully understand why yet as I do not fully understand the scoping mechanism. but it seems to "behave better" if you make sure all things that consume scopes are not long lived. Harry released a blog post related to this recently https://harrygordon.co.uk/blog/not-thread-safe-obviously/ I don't think it's a full fix, but it sure reduces the chance of these errors occuring.
o
Cheers both, I'll defo have a read of that and I'll try changing my repos to Singletons and report back 🙂
4 Views