0

iam using ninject.web in my aspx page in this way

my problem is with Nhibernate session management.

this is my ninject module:

public override void Load()
{
    Bind<IUnitOfWork>().To<UnitOfWork>();
    Bind<IAttivitaRepository>().To<AttivitaRepository>();
}

the page_load and quite every button in a single page create and dispose a unit of work at this way:

using (iuow)
{
    iuow.DoSomething();
    iuow.SaveAll();
}

in pageLoad works, but every other attempt in the page to use iuow with a new Using block, return that session is closed

this is my UoW impl:

public UnitOfWork()
        {
            _nhHelper = new SessionFactory();
            InizializzaSessione();
            _transaction = _session.BeginTransaction();
        }

        private void InizializzaSessione()
        {
            if (_session == null)
            {
                _session = _nhHelper.OpenSession();
            }
            Area = new AreaRepository(this._session);
            Attivita = new AttivitaRepository(this._session);           
            Societa = new SocietaRepository(this._session);
            Persona = new PersonaRepository(this._session);         
        }

        /// <summary>
        /// Salva le modifiche sulla base dati
        /// </summary>
        public void SaveAll()
        {
            if (_transaction != null)
            {
                _transaction.Commit();              
                _transaction = null;
            }
        }

it seems to me that iuow is resolved (whith a call to New) only at page load, so every new attempt to create Uow return last used one with session disposed.

before attimpting to use ninject what i do is simply:

using (Iuow = new UnitOfWork())
{
    ....
}

and all works fine

p.s. i have to remove InRequestScope from binding since it prevent even the page load to work

Community
  • 1
  • 1
gt.guybrush
  • 1,320
  • 3
  • 19
  • 48
  • 1
    I have never used ninject but surely the using statement is closing the session, remove this and close the session when you are finished. – Scrobi Jun 24 '16 at 14:06
  • i want that the new using block create a new UnitOfWork, not reuse existing one – gt.guybrush Jun 24 '16 at 14:59

1 Answers1

1

replace

using (iuow)
{
    ...
}

by

using (IResolutionRoot.Get<IUnitOfWork>())
{
    ...
}

Whereas you can inject IResolutionRoot into your classes. No extra bindings necessary (it's a Ninject type).

Caveat: this is service locator.

Alternatively you can hide the IResolutionRoot.Get<IUnitOfWork>() behind an IUnitOfWorkFactory which you can either implement manually or use Ninject.Extensions.Factory to do it for you.

Example

using Ninject;
using Ninject.Syntax;

namespace NinjectTest.SO38013150
{
    public interface IUnitOfWork { }

    internal class UnitOfWork : IUnitOfWork { }

    public interface IUnitOfWorkFactory
    {
        IUnitOfWork Create();
    }

    internal class UnitOfWorkFactory : IUnitOfWorkFactory
    {
        private readonly IResolutionRoot resolutionRoot;

        public UnitOfWorkFactory(IResolutionRoot resolutionRoot)
        {
            this.resolutionRoot = resolutionRoot;
        }

        public IUnitOfWork Create()
        {
            return this.resolutionRoot.Get<IUnitOfWork>();
        }
    }
}

with a test showing that it works (this uses xunit for testing and FluentAssertions for assertions.. they are nuget packages):

using FluentAssertions;
using Ninject;
using Xunit;

namespace NinjectTest.SO38013150
{
    public class Test
    {
        [Fact]
        public void Foo()
        {
            var kernel = new StandardKernel();
            kernel.Bind<IUnitOfWork>().To<UnitOfWork>();
            kernel.Bind<IUnitOfWorkFactory>().To<UnitOfWorkFactory>();

            var factory = kernel.Get<IUnitOfWorkFactory>();

            var unitOfWork1 = factory.Create();
            var unitOfWork2 = factory.Create();

            unitOfWork1.Should().NotBeSameAs(unitOfWork2);
        }
    }
}

The code is also available as part of my examples collection, here

Community
  • 1
  • 1
BatteryBackupUnit
  • 12,934
  • 1
  • 42
  • 68
  • IUnitOfWorkFactory must be implemented in my Nhibernate project or it's a simple ninject encapsulation in web project of IResolutionRoot method? – gt.guybrush Jun 24 '16 at 15:17
  • 1
    @gt.guybrush It's a simple encapsulation of `IResolutionRoot.Get()` - just a few lines of code. Should be placed in the composition root = the web project. – BatteryBackupUnit Jun 24 '16 at 15:19
  • i find kernel.Bind().ToFactory(); but think is not my case, other example mean creating an interface and a specific implementation, how can i do it in composition root? – gt.guybrush Jun 24 '16 at 15:42
  • find now here: http://stackoverflow.com/questions/10285946/ioc-ninject-and-factories i will try it – gt.guybrush Jun 24 '16 at 15:46
  • give error: IResolutionRoot does not contain definition for Get() – gt.guybrush Jun 27 '16 at 07:03
  • @gt.guybrush the low ratio of accepted answers to your questions don't motivate me to spoon-feed you a solution, especially given that very similar questions have been handled on SO before. – BatteryBackupUnit Jun 27 '16 at 08:08
  • i always accept solution that resolve problem. when answer are useful but not resolutive i upvote them (and some of them are mine). at moment here i see only some non compiling code, even if it's an idea to follow. what's the similar question? i search a couple of days before making mine – gt.guybrush Jun 27 '16 at 08:23
  • 1
    @gt.guybrush i did a quick check and the search for "[ninject] unit of work factory" returns a lot of search results. Some of them even are relevant to what you're asking.. of course looking through all of these will take 1-4 hours of effort easily. Giving you the benefit of the doubt i have extended my answer with a complete working example, including `using` directives to make sure that that's not a stumbling block... – BatteryBackupUnit Jun 27 '16 at 11:28
  • i was using it directly without creating an instance of IResolutionRoot. so in my app i have to use IUnitOfWorkFactory and not IUnitOfWork. that was what i misunderstood, I thought I could use iuow transparently and that ninject resolved it calling factory... – gt.guybrush Jun 27 '16 at 13:03
  • @gt.guybrush By convention, when something starts with an `I`, it's an interface - and interface never have fields/properties/methods which can be accessed statically. A search for `IResolutionRoot` would have shown that, too. – BatteryBackupUnit Jun 27 '16 at 13:06
  • do you think that the module where i define all my repository binding can be a good place to keep this factory? – gt.guybrush Jun 27 '16 at 13:22
  • 1
    @gt.guybrush that's a good place to keep the binding of the factory. The factory interface should probably be where the `IUnitOfWork` interface is. The implementation should be in the web-application project. – BatteryBackupUnit Jun 28 '16 at 06:17
  • ok. I was wondering a different idea: can be possible to hide factory to my web application? i ask for IUnitOfWork and ninject instead of calling the implementation calls a method thats do resolutionRoot.Get(). in that way don't need to remeber to call IuowFactory instead of Iuow – gt.guybrush Jun 28 '16 at 06:31
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/115786/discussion-between-batterybackupunit-and-gt-guybrush). – BatteryBackupUnit Jun 28 '16 at 06:34
  • chat is locked by my office's proxy :( i can try Factory Methods with delegate, like the example Bind().ToMethod(context => new Sword()); and ask new question if find problem – gt.guybrush Jun 28 '16 at 06:39
  • 1
    @gt.guybrush that doesn't make any sense at all. There still will be exactly **1** instance which can't be used as soon as it is `.Dispose()`d (which, incidentally, is what happens at the end of each `using` block!). You need a mechanism to create multiple instances per owner-object (page?). That's the factory - which is a replacement for the `new` operator. – BatteryBackupUnit Jun 28 '16 at 07:56