Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ISingletonDependency and repositories #1972

Closed
nandaccio opened this issue Mar 24, 2017 · 7 comments
Closed

ISingletonDependency and repositories #1972

nandaccio opened this issue Mar 24, 2017 · 7 comments

Comments

@nandaccio
Copy link

nandaccio commented Mar 24, 2017

Hi,

with reference to #61 , I'm not sure if I'm going something wrong, if there's an issue or if everything is working as expected.

I'm injecting a repository into the application service:

public class TestAppService : TestAppServiceBase, ITestAppService
    {
        private readonly MongoRepository<Customer> _customerRepository;	
        public TestAppService (MongoRepository<Customer> repo)
        {
            _customerRepository = repo;
        }
...

Where MongoRepository inherits from:

 public interface IMongoRepository<T> : IRepository where T : MongoEntity

as follows:

public class MongoRepository<T> : ISingletonDependency, IMongoRepository<T> where T : MongoEntity
    {
        protected IMongoDatabase _db;
        protected IMongoCollection<T> _collection;
        private static PluralizationService p = PluralizationService.CreateService(new System.Globalization.CultureInfo("en-us"));

        public MongoRepository()
        {
            if (MongoConnection.ConnectionString != null)
            {
                MongoUrl mongoUrl = new MongoUrl(MongoConnection.ConnectionString);
                var client = new MongoClient(mongoUrl);
                _db = client.GetDatabase(mongoUrl.DatabaseName);
                SetCollectionName();
            }
        }

Everything is working, aside that the constructor of MongoRepository is invoked when the MongoRepository dependency must be resolved by TestAppService. Having inherited MongoRepository from ISingletonDependency, I'd expect a singleton lifetime cycle for the repository to be used.

Note: IRepository is Abp.Domain.Repositories.IRepository, while MongoEntity is my own definition of a MongoDB entity.

@nandaccio
Copy link
Author

nandaccio commented Mar 24, 2017

It seems that there's a different behaviour based on how I resolve the application service.

Case 1)

_testService = IocManager.Instance.Resolve<ITestAppService>();

Case 2)

public class AboutController : TestControllerBase
	{
        private readonly ITestAppService _testService;

        public AboutController(ITestAppService TestService)
        {
            _testService = TestService;
        }

If the application service is resolved via the IocManager static Instance then the constructor of MongoRepository is not invoked, while if I obtain the TestAppService like in case 2) then a new instance of MongoRepository is created, despite being derived from ISingletonDependency.

Is this the expected behaviour?

@nandaccio
Copy link
Author

nandaccio commented Mar 24, 2017

If MongoRepository< Customer > is registered explicitely then the singleton lifetime is actually enforced:

 IocManager.Register(typeof(MongoRepository<Customer>), Abp.Dependency.DependencyLifeStyle.Singleton);

Example:

  public override void Initialize()
        {
            IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());

            IocManager.Register(typeof(MongoRepository<Customer>), Abp.Dependency.DependencyLifeStyle.Singleton);
        }

But it seems that I'm following the naming convention:

"Naming conventions are very important here. For example you can change name of PersonAppService to MyPersonAppService or another name which contains 'PersonAppService' postfix since the IPersonAppService has this postfix. But you can not name your service as PeopleService. If you do it, it's not registered for IPersonAppService automatically (It's registered to DI framework but with self-registration, not with interface), so, you should manually register it if you want."

with

   public interface IMongoRepository<T> : IRepository where T : MongoEntity

and
   public class MongoRepository<T> : ISingletonDependency, IMongoRepository<T> where T : MongoEntity

@nandaccio
Copy link
Author

Now it's working, but I had to declare the generic repository as follows:

  public interface IMongoRepository<T> where T : MongoEntity

and

 public class MongoRepository<T> : IMongoRepository<T> where T : MongoEntity 

Then I registered it with:

IocManager.Register(typeof(IMongoRepository<>), typeof(MongoRepository<>), Abp.Dependency.DependencyLifeStyle.Singleton);

Is this how it is supposed to work to have repositories with the DependencyLifeStyle.Singleton lifecycle?

Thanks

@hikalkan
Copy link
Member

It was a little long to read, but I can say that: When you inherit from IRepository, you are implicitly inherit from ITransientDependency. So, when you also implement ISingletonDependency, you have both implemented, and I don't know how it works in that case. It may not be consistent.

I definitely suggest to make repositories transient! Repositories should be transient normally. When you make it singleton you will deal with multi-threading since all threads use the same instance.

If you really want to make it singleton, then do not inherit from IRepository or manually register it before RegisterAssemblyByConvention.

@nandaccio
Copy link
Author

Thanks for your feedback,

I did not want to create a new instance of the repository each time the methods of application layer are invoked, because my repository is constructed as follows and I wanted to use the same instance for all calls:

  public class MongoRepository<T> : IMongoRepository<T> where T : MongoEntity /* ISingletonDependency, */ 
    {
        protected IMongoDatabase _db;
        protected IMongoCollection<T> _collection;
        private static PluralizationService p = PluralizationService.CreateService(new System.Globalization.CultureInfo("en-us"));

        public MongoRepository()
        {      
            if (MongoConnection.ConnectionString != null)
            {
                MongoUrl mongoUrl = new MongoUrl(MongoConnection.ConnectionString);
                var client = new MongoClient(mongoUrl);
                _db = client.GetDatabase(mongoUrl.DatabaseName);
                SetCollectionName();
            }
        }  
<...>
 public IEnumerable<T> Search(Expression<Func<T, bool>> predicate)
        {
            return _collection.AsQueryable<T>().Where(predicate.Compile());
        }

        public IEnumerable<T> GetAll()
        {
            return _collection.AsQueryable();
        }

        public IEnumerable<T> FindAll()
        {
            return _collection.Find(_ => true).ToList();
        }

Registering the repository (no longer inherited from IRepository) with:

IocManager.Register(typeof(IMongoRepository<>), typeof(MongoRepository<>), Abp.Dependency.DependencyLifeStyle.Singleton);

Seems to work.

@hikalkan
Copy link
Member

Thanks for sharing your solution.

@ryoldash
Copy link

ryoldash commented Jan 4, 2018

@hikalkan Thanks for your great AbpBoilerplate framework. @nandaccio It would be nice if we have step by step tutorial related with creating module for MongoRepository and consuming it from UI layer for Abp.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants