Alternative solution to use "ApplicationContext.Current.DatabaseContext.Database;" in Umbraco 8
I have been using
// var db = ApplicationContext.Current.DatabaseContext.Database;
for accessing my db in Umbraco 7 , but it can't be done on Umbraco 8
In your constructor you take IScopeAccessor, that holds an AmbientScope that has a Database-property
public class MyWhatever{
private readonly IScopeAccessor _scopeAccessor
public MyWhatever(IScopeAccessor scopeAccessor){
_scopeAccessor=scopeAccessor;
}
public int Count(){
var count = _scopeAccessor.AmbientScope.Database.ExecuteScalar<int>("SELECT COUNT(*) FROM table");
return count;
}
}
To give you the full picture, my full class looks like this:
using System.Web.Mvc;
using Cultiv8.Core.Models;
using Umbraco.Core.Scoping;
using Umbraco.Web.Models;
using Umbraco.Web.Mvc;
namespace Cultiv8.Core.Controllers
{
public class BlogPostController : RenderMvcController
{
private IScopeProvider _scopeProvider;
public BlogPostController(IScopeProvider scopeProvider)
{
_scopeProvider = scopeProvider;
}
public ActionResult BlogPost(ContentModel model)
{
using (var scope = _scopeProvider.CreateScope())
{
//DB Stuff
scope.Database.ExecuteScalar<int>("SELECT COUNT(*) FROM table");
//Always complete scope
scope.Complete();
}
var blogPostModel = new BlogPostModel(model.Content);
return CurrentTemplate(blogPostModel);
}
}
}
Your question depends a little bit on what kind of class you're working in but this would be the general pattern.
To complement Sebastiaan's excellent answer: a Scope should always be obtained from a IScopeProvider. This provider manages nesting scopes, scope completion, etc.
Now, internally, getting a scope makes it the "ambient" scope (until it is disposed) and that is what IScopeAccessor manages: the "ambient" scope. So _scopeAccessor.AmbientScope is indeed going to get you a scope... in some cases. It's going to get you the ambient scope, if you already are in a scope. But it's not going to create a scope, ie it could very well return null.
So... you don't want to use IScopeAccessor. Use IScopeProvider.
And then, about scope completion. Scopes wrap a database transaction, and this allows us to, for instance, database-lock the content tree or other things, for the duration of the transaction, thus bringing some concurrency-safety that was missing in v7.
When you nest scopes, each scope of the chain relies on the unique database connection (and transaction) that was created for the top scope. And the connection is closed when this top scope is disposed.
What happens then depends on whether the scope has been completed. If it's been completed, the transaction is committed, else it's rolled back.
For nested scopes: if any nested scope is not completed, then the top scope is considered as not-completed and the transaction is rolled back. So you always want to complete any scope you use, even if you're only doing reads (not writing anything).
If you know you're only going to read, you can use:
using (scopeProvider.CreateScope(autoComplete: true))
{
// no need to scope.Complete()
}
Be careful though: the scope will be completed no matter what, even if an exception is thrown from within the using block.
How would you go about this if you had an extra layer, such as a simple repository? So would you pass an IScope to the repository to initialise it?
Say it was like this very simplified example:
public class MyRepo
{
private readonly IScope _scope;
public MyRepo(IScope scope)
{
this._scope = scope;
}
public IEnumerable<string> GetUserNames()
{
return this._scope.Database.Fetch<string>("SELECT userName FROM umbracoUser ORDER BY userName");
}
public IEnumerable<int> GetIds()
{
return this._scope.Database.Fetch<int>("SELECT id FROM cmsContent");
}
}
How would you initialise the repository once? Could you do it in the Controller's constructor like this, which doesn't seem right?
public class MyController : RenderMvcController
{
private IScopeProvider _scopeProvider;
private MyRepo _myRepo;
public MyController(IScopeProvider scopeProvider)
{
this._scopeProvider = scopeProvider;
using (var scope = _scopeProvider.CreateScope())
{
_myRepo = new MyRepo(scope);
}
}
public ActionResult GetSomeUserNames(ContentModel model)
{
var names = _myRepo.GetUserNames();
return CurrentTemplate(model);
}
public ActionResult GetSomeId(ContentModel model)
{
var ids = _myRepo.GetIds();
return CurrentTemplate(model);
}
}
Or would you need to initialise the scope in every call in the controller eg.
public ActionResult GetSomeUserNames(ContentModel model)
{
using (var scope = _scopeProvider.CreateScope())
{
_myRepo = new MyRepo(scope);
var names = _myRepo.GetUserNames();
scope.Complete();
}
return CurrentTemplate(model);
}
Or is there some other better way? Can you access this AmbientScope you mentioned? Maybe someway of using DI to register the repo?
Should the ScopeProvider always be accessed via the parameter or can it be accessed via Current as well, in e.g. SurfaceController? Not sure if there is a different?
using (var scope = Current.ScopeProvider.CreateScope())
{
//DB Stuff
scope.Database.ExecuteScalar<int>("SELECT COUNT(*) FROM table");
//Always complete scope
scope.Complete();
}
public class MyRepository : IMyRepository
{
private readonly IScopeAccessor _scopeAccessor;
public MyRepository(IScopeAccessor scopeAccessor)
{
_scopeAccessor = scopeAccessor;
}
private IUmbracoDatabase Database = _scopeAccessor.AmbientScope.Database;
private void DoSomething()
{
Database.Execute(...);
}
}
And they are registered in DI. So you can directly inject the repository in your service or (god forbit) controller constructor:
public MyController(IMyRepository myRepository)
{ ... }
In order to use it, you'll need to ensure there is an ambient scope:
using (var scope = _scopeProvider.CreateScope())
{
_myRepository.DoSomething();
scope.Complete();
}
Because the repository does not capture anything but the scope accessor, which is a singleton, it can also be registered as a singleton, thus reducing allocations.
OK, so I've created MyRespository like you suggested, so it takes a IScopeAccessor. I've then registered it as a singleton like this:
public class MyRepoComposer : IUserComposer
{
public void Compose(Composition composition)
{
composition.RegisterUnique<IMyRepository, MyRepository>();
}
}
I've then injected the IMyRepository into the constructor of a controller (just to test!).
However, in MyRepository the _scopeAccessor.AmbientScope is null.
The bit I don't quite get is how you create the ambient scope as in your example. You say "in order to user it you'll need to create an ambient scope" but I'm not clear where _scopeProvider is coming from in your example.
Assume I have a controller that injects my repo like this:
then something like get looks like (using custom GetBaseQuery / GetBaseWhereClause functions)
public virtual TModel Get(int id)
{
var sql = GetBaseQuery(false)
.Where(GetBaseWhereClause(), new { Id = id });
var dto = Database.FirstOrDefault<TDTOModel>(sql);
if (dto == null) return default(TModel);
return Mapper.Map<TModel>(dto);
}
I think this is right (taking into consideration the autoclose stuff stephen mentioned)
Thanks, just after posting I did just that and it does work. So thanks for your help! :)
But.... but....
It doesn't seem quite right to me that you need to remember to wrap every call to the repo in a scope otherwise it fails. What if someone else injects it and doesn't do that?
So another developer comes along, injects IMyRepository and then calls _myRepo.DoSomething() and boom it blows up and they've no idea why. Isn't there a way you can just call MyRepo without needing to know or worry about scope?
The general pattern is that you don't expose your repository to "general other developers" - you expose services, which internally create scopes and invoke repositories.
Whoever uses the repository directly should know about the constraint.
OK, yeah, I get that to an extent. You might not make your repository layer public but only expose it internally via a service layer (I was trying to keep this example simple). But it still feels wrong to me that the consumer of a class needs to know to wrap it before calling it. Isn't this known as temporal coupling, which I thought should be avoided?
In my case I'm just looking at a small package that has a few database calls, and having multiple tiers seems a little OTT, as basically the service layer would just be calling each method in the repo, but having to wrap each call in a scope, which just seems like a lot of unnecessary code to me.
Is having a repo DI'd in this instance even a good idea? Maybe the service later should be, but maybe not the repo? I guess I'd just like some guidance on the best way for package makers to proceed with stuff like this.
Hello Kevin,
I was just about to test this since I am extending my current Umbraco database.
I'm kinda stuck here because I can't get a grip of the whole scenario.
In your "MyRepositoryBase" - Why would you have repository methods there? (Why isn't the repository methods in each repository? example ProductRepository/ UserRepository?
Where is the "Public virtual TModel Get(int id) ? Where should this be run? in a controller or a handler/manager?
Is the only purpose of "MyRepositoryBase" to validate and set up the properties for instantiating the database?
Yeah out of context i can see how that is confusing, the MyRepositoryBase class would be inherited by your ProductRepository or UserRepository, its just that the base get methods could then be shared between them.
Alright, now I see how they are connected. Thank you so much! :)
Regarding DI.. How would you inject the generic types?
BaseRepository<TModel> : IBaseRepository<TModel> where TModel : class
Right now I'm getting the "Make sure that the controller has a parameterless public constructor" Since I'm using the repository directly from my controller.
Do you have any ideas on how I set this up correctly in the compositons?
using (var scope = _scopeProvider.CreateScope())
{
_myRepo = new MyRepo(scope);
}
would cause interesting errors. You are capturing scope in _myRepo but when exiting the using block, scope is disposed = any time you try to use your repository, you'll get an object disposed exception of some sort.
Thanks, Stephen, I could see that initialising the repo with the scope was wrong, just wasn't sure of the best alternative. I did try and look at some of the core stuff, but it was quite complex for my needs. I'll try your approach you mentioned.
This means that whatever happens inside of the using block, the scope will complete - if that is ok, for instance because you are only reading, or you are ok completing even if you are doing writes which may throw, then fine.
In Core, we use it for reads, but never for writes.
Alternative solution to use "ApplicationContext.Current.DatabaseContext.Database;" in Umbraco 8
I have been using
// var db = ApplicationContext.Current.DatabaseContext.Database; for accessing my db in Umbraco 7 , but it can't be done on Umbraco 8
use DI
In your constructor you take IScopeAccessor, that holds an AmbientScope that has a
Database
-propertyYou should use something like this:
You will notice the
_scopeProvider
there, where does it come from?This is where dependency injection comes in, the class that I'm working in is asking for a
_scopeProvider
in the constructor, so like this:To give you the full picture, my full class looks like this:
Your question depends a little bit on what kind of class you're working in but this would be the general pattern.
Does this make sense at all?
To complement Sebastiaan's excellent answer: a
Scope
should always be obtained from aIScopeProvider
. This provider manages nesting scopes, scope completion, etc.Now, internally, getting a scope makes it the "ambient" scope (until it is disposed) and that is what
IScopeAccessor
manages: the "ambient" scope. So_scopeAccessor.AmbientScope
is indeed going to get you a scope... in some cases. It's going to get you the ambient scope, if you already are in a scope. But it's not going to create a scope, ie it could very well returnnull
.So... you don't want to use
IScopeAccessor
. UseIScopeProvider
.And then, about scope completion. Scopes wrap a database transaction, and this allows us to, for instance, database-lock the content tree or other things, for the duration of the transaction, thus bringing some concurrency-safety that was missing in v7.
When you nest scopes, each scope of the chain relies on the unique database connection (and transaction) that was created for the top scope. And the connection is closed when this top scope is disposed.
What happens then depends on whether the scope has been completed. If it's been completed, the transaction is committed, else it's rolled back.
For nested scopes: if any nested scope is not completed, then the top scope is considered as not-completed and the transaction is rolled back. So you always want to complete any scope you use, even if you're only doing reads (not writing anything).
If you know you're only going to read, you can use:
Be careful though: the scope will be completed no matter what, even if an exception is thrown from within the
using
block.Hi Guys,
How would you go about this if you had an extra layer, such as a simple repository? So would you pass an
IScope
to the repository to initialise it?Say it was like this very simplified example:
How would you initialise the repository once? Could you do it in the Controller's constructor like this, which doesn't seem right?
Or would you need to initialise the scope in every call in the controller eg.
Or is there some other better way? Can you access this AmbientScope you mentioned? Maybe someway of using DI to register the repo?
... so much for learning by reading the code.
Thx for clarifying guys :-)
Should the ScopeProvider always be accessed via the parameter or can it be accessed via
Current
as well, in e.g.SurfaceController
? Not sure if there is a different?If you can avoid using
Current
at all then try to avoid it.Core's repository look like
And they are registered in DI. So you can directly inject the repository in your service or (god forbit) controller constructor:
In order to use it, you'll need to ensure there is an ambient scope:
Because the repository does not capture anything but the scope accessor, which is a singleton, it can also be registered as a singleton, thus reducing allocations.
Making sense?
Hi Stephen,
OK, so I've created
MyRespository
like you suggested, so it takes aIScopeAccessor
. I've then registered it as a singleton like this:I've then injected the
IMyRepository
into the constructor of a controller (just to test!).However, in
MyRepository
the_scopeAccessor.AmbientScope
is null.The bit I don't quite get is how you create the ambient scope as in your example. You say "in order to user it you'll need to create an ambient scope" but I'm not clear where
_scopeProvider
is coming from in your example.Assume I have a controller that injects my repo like this:
How do I then use that repository in controller methods so I have an ambient scope? eg. how would the following work?
PS. Sorry for all the questions!
You need an ambient scope:
Thanks, but where does
_scopeProvider
come from? How does that get into the controller?Inject!
Hi Dan,
my copied from the core, and simplified a bit serivce / repo looks like this :
So my services are inheriting something like :
and my repositories are inheriting this (slightly more complex and this is where the ambient scope is created ... inside the repository class
then something like
get
looks like (using customGetBaseQuery
/GetBaseWhereClause
functions)I think this is right (taking into consideration the autoclose stuff stephen mentioned)
Thanks, just after posting I did just that and it does work. So thanks for your help! :)
But.... but....
It doesn't seem quite right to me that you need to remember to wrap every call to the repo in a scope otherwise it fails. What if someone else injects it and doesn't do that?
So another developer comes along, injects
IMyRepository
and then calls_myRepo.DoSomething()
and boom it blows up and they've no idea why. Isn't there a way you can just callMyRepo
without needing to know or worry about scope?You are also able to control how a database Connection behaves this way in .Net Framework, so it’s not unheard of.
But I agree it’s not very SOLID
The general pattern is that you don't expose your repository to "general other developers" - you expose services, which internally create scopes and invoke repositories.
Whoever uses the repository directly should know about the constraint.
At least that's how it works in Core.
OK, yeah, I get that to an extent. You might not make your repository layer public but only expose it internally via a service layer (I was trying to keep this example simple). But it still feels wrong to me that the consumer of a class needs to know to wrap it before calling it. Isn't this known as temporal coupling, which I thought should be avoided?
In my case I'm just looking at a small package that has a few database calls, and having multiple tiers seems a little OTT, as basically the service layer would just be calling each method in the repo, but having to wrap each call in a scope, which just seems like a lot of unnecessary code to me.
Is having a repo DI'd in this instance even a good idea? Maybe the service later should be, but maybe not the repo? I guess I'd just like some guidance on the best way for package makers to proceed with stuff like this.
Hello Kevin, I was just about to test this since I am extending my current Umbraco database.
I'm kinda stuck here because I can't get a grip of the whole scenario.
In your "
MyRepositoryBase
" - Why would you have repository methods there? (Why isn't the repository methods in each repository? exampleProductRepository
/UserRepository
?Where is the "
Public virtual TModel Get(int id)
? Where should this be run? in a controller or a handler/manager?Is the only purpose of "
MyRepositoryBase
" to validate and set up the properties for instantiating the database?Thanks!
Hi Alexander,
Yeah out of context i can see how that is confusing, the MyRepositoryBase class would be inherited by your ProductRepository or UserRepository, its just that the base get methods could then be shared between them.
i have a slightly more detailed version in a git hub repo : https://github.com/KevinJump/DoStuffWithUmbraco/tree/master/Src/DoStuff.Core/RepoPattern
that hopefully allows you to see it in context.
Hello Kevin!
Alright, now I see how they are connected. Thank you so much! :)
Regarding DI.. How would you inject the generic types?
Right now I'm getting the "Make sure that the controller has a parameterless public constructor" Since I'm using the repository directly from my controller.
Do you have any ideas on how I set this up correctly in the compositons?
By the way, this:
would cause interesting errors. You are capturing
scope
in_myRepo
but when exiting theusing
block,scope
is disposed = any time you try to use your repository, you'll get an object disposed exception of some sort.Just checking - is this OK.
The
autoComplete
parameter makes it a bit neater - but i am sort of assuming it worksThanks, Stephen, I could see that initialising the repo with the scope was wrong, just wasn't sure of the best alternative. I did try and look at some of the core stuff, but it was quite complex for my needs. I'll try your approach you mentioned.
No problem - following this thread, as it may turn into a blog post - lots of "obviously not obvious" things that you are discovering here.
This means that whatever happens inside of the
using
block, the scope will complete - if that is ok, for instance because you are only reading, or you are ok completing even if you are doing writes which may throw, then fine.In Core, we use it for reads, but never for writes.
is working on a reply...