Tags: , , , , , , | Categories: ASP.Net, C#, MVC, NHibernate, Ninject Posted by Admin on 6/13/2011 12:55 PM | Comments (12)

We eventually managed to get Ninject,Fluent NHibernate, NHibernate.Linq and MVC3 to play nicely together. Each of these libraries has its issues when it comes to playing nicely mainly due to dependencies mis-matches or due to a lack of instruction.

Firstly, Ninject. We installed Ninject into our sample application using the Package Manager Console.

Install-Package Ninject
Install-Package Ninject.Web
Install-Package Ninject.MVC3

We missed Ninject.MVC3 first time around which cost us about two hours of head scratching so remember to install it.

Once all three Ninject libraries are installed into your application you should have a new generated file App_Start/NinjectMVC3.cs, this is where you load your Ninject Module(s) into your application and where the magic construction injection takes place for your controllers (amongst other things).

The next step seems to be widely documented on the net pointless if you're using NinjectMVC3; modifying your Global.asax file to enable Ninject to do its thing is no longer required and to configure NHibernate fluently.

public class MvcApplication : HttpApplication
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new HandleErrorAttribute());
    }

    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        routes.MapRoute(
            "Default", // Route name
            "{controller}/{action}/{id}", // URL with parameters
            new { controller = "Person", action = "Index", id = UrlParameter.Optional } // Parameter defaults
        );

    }
}

Next we need to configure Ninject so that it knows what concrete implementations of interfaces to inject. This is done by inheriting from NinjectModule and overriding the Load() method.

public override void Load()
{
    this.Bind<IRepository>().To<NHRepository>().InRequestScope(); //.InSingletonScope(); <-- Singleton scope doesn't work with ISession in request scope!
    this.Bind<ISessionFactory>().ToMethod(x => Database.CreateSessionFactory()).InSingletonScope();
    this.Bind<ISession>().ToMethod(x => context.Kernel.Get<ISessionFactory>().OpenSession()).InRequestScope();
    this.Bind<PersonController>().ToSelf();
}

In this case whenever a constructor requires an implementation of IRepository the same an instance of NHRepository is supplied by the InSingletonScope modifier. We're also binding our NHibernate ISession to the GetCurrentSessionOpenSession() method of the ISessionFactory (which being static prevents re-initialization of SessionFactory - a very expensive operation) and binding the PersonController to itself.

Finally we need Ninject to load our module into the application when the application starts, this is done in NijnectMVC.cs by modifying the CreateKernel method.

private static IKernel CreateKernel()
{
    var kernel = new StandardKernel(new MvcApplicationNinjectModule());
    RegisterServices(kernel);
    return kernel;
}

As far as Ninject is concerned we're all sorted. We just need to create IRepository and implement this in NHRepository which is where NHibernate.Linq comes into the mix and then create our controller to call the repository.

We won't go into the details of IRepository and NHRepository other than to point out that Ninject injects our NHibernate Session into NHRepository in the constructor.

public interface IRepository
{
    IQueryable<T> Get<T>();
    IQueryable<T> Get<T, TKey>(params OrderByClause<T, TKey>[] orderBy);
    IQueryable<T> Get<T>(int pageSize, int pageIndex, out int recordCount);
    IQueryable<T> Get<T, TKey>(int pageSize, int pageIndex, out int recordCount, params OrderByClause<T, TKey>[] orderBy);
}
public class NHRepository : IRepository
{
private ISession session = null;

public IQueryable<T> Get<T>()
{
    return this.session.Query<T>();
}

public IQueryable<T> Get<T, TKey>(params OrderByClause<T, TKey>[] orderBy)
{
    var query = this.session.Query<T>();
    foreach (var order in orderBy)
    {
        switch (order.Direction)
        {
            case OrderByDirection.Descending:
                query = query.OrderByDescending(order.Expression);
                break;
            default:
                query = query.OrderBy(order.Expression);
                break;
        }
    }

    return query;
}

public IQueryable<T> Get<T>(int pageSize, int pageIndex, out int recordCount)
{
    recordCount = this.session.Query<T>().Count();
    return this.session.Query<T>().Skip(pageSize * pageIndex).Take(pageSize);
}

public IQueryable<T> Get<T, TKey>(int pageSize, int pageIndex, out int recordCount, params OrderByClause<T, TKey>[] orderBy)
{
    recordCount = this.session.Query<T>().Count();
    var query = this.session.Query<T>();
    foreach (var order in orderBy)
    {
        switch (order.Direction)
        {
            case OrderByDirection.Descending:
                query = query.OrderByDescending(order.Expression);
                break;
            default:
                query = query.OrderBy(order.Expression);
                break;
        }
    }

    return query.Skip(pageSize * pageIndex).Take(pageSize);
}

public NHRepository(ISession session)
{
    this.session = session;
}

Finally we come to the controller which needs an instance of IRepository to fetch its data from.

public class PersonController : Controller
{
    private IRepository repository;

    public PersonController(IRepository repository)
    {
        this.repository = repository;
    }

    [HttpGet]
    public ActionResult Index(int? pageIndex)
    {
        int actualPageIndex = pageIndex.GetValueOrDefault(0);
        int recordCount = 0;
        var people = this.repository.Get<Person, dynamic>(10, actualPageIndex, out recordCount, new OrderByClause<Person, dynamic>(c => c.DateOfBirth.Value, OrderByDirection.Descending), new OrderByClause<Person, dynamic>(c => c.Surname, OrderByDirection.Ascending), new OrderByClause<Person, dynamic>(c => c.Forename, OrderByDirection.Ascending));
        int pageCount = (int)Math.Ceiling((double)recordCount / 10);
        return View(new PagedListViewModel<Person>(people.ToList(), actualPageIndex, pageCount));
    }

}

Ninject is again doing its magic by injecting an (singleton) instance of NHRepository into our constructor for us.

So where were the issues? Well if you use the package manager to get all the Fluent NHibernate and NHibernate.Linq libraries you'll see that Fluent NHibernate uses version 3.1 of NHibernate but NHibernate.Linq is complied against version 2.1, and NHibernate.Linq is complied against version 3.5 of System.Xml.Linq whereas our application is using version 4.0. To fix these mis-matches we can configure our application to substitute any request for a dependancy with a newer version of the same library. This is done in web|app.config

<runtime>
  <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
    <dependentAssembly>
      <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
      <bindingRedirect oldVersion="1.0.0.0-2.0.0.0" newVersion="3.0.0.0" />
    </dependentAssembly>
    <dependentAssembly>
      <assemblyIdentity name="System.Xml.Linq" publicKeyToken="b77a5c561934e089" />
      <bindingRedirect oldVersion="1.0.0.0-3.5.0.0" newVersion="4.0.0.0" />
    </dependentAssembly>
    <dependentAssembly>
      <assemblyIdentity name="NHibernate" publicKeyToken="aa95f207798dfdb4" />
      <bindingRedirect oldVersion="2.1.0.4000-2.1.2.4000" newVersion="3.1.0.4000" />
    </dependentAssembly>
  </assemblyBinding>
</runtime>

Comments (12) -

Rowerki dla dzieci Poland on 6/13/2011 8:25 PM Very good code Smile Thanks
Admin United Kingdom on 6/23/2011 8:35 AM We discovered an issue when trying to have a singleton repository what is injected with a request scoped session - it doesn't work. This seems obvious now but took a little thinking about. Essentially the first request initialises the singleton repository with it's session but any subsequent requests don't provide a session (it's a singleton afterall) but when the repository tries to use the injected session it is now out of scope a is therefore closed. The solution (for now) was to not have singleton repositories but have an instance per session had let Ninject handle the set-up and tear-down. How well this scales is something for the future. The post have been edited to reflect this issue.
cellulite burning exercises United States on 7/19/2011 1:45 AM I'm really enjoying the design and layout of your site. It's a very easy on the eyes which makes it much more enjoyable for me to come here and visit more often. Did you hire out a developer to create your theme? Outstanding work!
Magician United States on 7/19/2011 8:46 AM Nice! Great article! Thank you.
Future Web Design on 9/28/2011 12:30 AM Hey,

Thanks  for the share, its Awesome.

Regards,
Future Web Design
Björn Boxstart Netherlands on 12/16/2011 4:17 PM Hello,

Nice article! I'm trying it out right now, but am I the only one who does not know of which package the OrderByClause object comes from?

Kind regards,
Björn
Scott United Kingdom on 12/19/2011 10:39 AM Nice article! I'm trying it out right now, but am I the only one who does not know of which package the OrderByClause object comes from?

OrderByClause is a generic class created by real web developers. We've actually replaced it with a new class OrderByExpression which looks something like

public class OrderByExpression<T>
{
    public Expression<Func<T, dynamic>> expression { get; private set; }
    public SortDirection direction { get; private set; }

    public OrderByExpression(Expression<Func<T, dynamic>> expression, SortDirection direction)
    {
        this.expression = expression;
        this.direction = direction;
    }
}

The SortDirection type is defined in System.Web.Helpers.
Web Design Dubai U.A.E. on 2/8/2012 7:10 AM This is my first opportunity to visit this website. I found some interesting things and I will apply to the development of my blog. Thanks for sharing useful information.
Jon United Kingdom on 2/24/2012 7:02 PM Great article!

Lead me nicely onto setting up validators for NHibernate! Smile

Thanks again!
ToddFoster37 United States on 3/24/2012 7:55 PM We installed Ninject into our sample application using the Package Manager Console.asax file to enable Ninject to do its thing is no longer required and to configure NHibernate fluently.cs by modifying the CreateKernel method. We just need to create IRepository and implement this in NHRepository which is where NHibernate.Linq comes into the mix and then create our controller to call the repository. This seems obvious now but took a little thinking about. How well this scales is something for the future. The post have been edited to reflect this issue. I found some interesting things and I will apply to the development of my blog. Thanks for sharing useful information.  I just hope that you dont lose your style because youre definitely one of the coolest bloggers out there.  Please keep it up because the internet needs someone like you spreading the word.  More people need to read this and understand this side of the story.  I cant believe youre not more popular because you definitely have the gift.  What I wouldnt give to be able to create a blog thats as interesting as this.  Im really happy that I stumbled across this in my search for something relating to this issue.  Its just great stuff all round.  Its so important to know how to construct a great blog to get people interested and youve done just that.  Your blog is just too important to be missed.  Im glad that I had the fortune to stumble across your blog.  This is definitely something people need to be up on.  Thanks so much for keeping the internet classy for a change.  Thank you for bringing more information to this topic for me.  Im truly grateful and really impressed.  But maybe you could a little more in the way of content so people could connect with it better.  Youve got an awful lot of text for only having one or two images.  I really enjoyed what you had to say.  Keep going because you definitely bring a new voice to this subject.  Not many people would say what youve said and still make it interesting.  Cant wait to see more of this from you.  This blog definitely has some information on topic that I just wasnt aware of.  Thanks for bringing this stuff to light.  Very refreshing blog and very refreshing ideas.  I love what youve got to say and the way you say it.  I dont think Ive met anyone who knows as much about this subject as you do.  Youre truly well informed and very intelligent.  You wrote something that people could understand and made the subject intriguing for everyone.  I think that everyones said the same thing that youve said over and over again.  I just feel like you know so much and know how to make people listen to what you have to say.  This blog is just too cool to be missed.  So much of it Ive never even thought of.  You sure did put a new twist on something that Ive heard so much about.  I dont believe Ive actually read anything that does this subject as good justice as you just did.  Not too many people would actually think about this the way you just did.HungaryIcelandIndiaIndonesiaIranIraqIrelandIslamic Republic of PakistanIsraelItalyJamaicaJapanJordanKazakhstanKenyaKoreaKuwaitKyrgyzstanLatviaLebanonLibyaLiechtensteinLithuaniaLuxembourgMacao S.My bro saved this webpage for me and I have been going through it for the past couple hours. This is really going to help me and my classmates for our class project. By the way, I enjoy the way you write. <a href="http://blogseu.com">stiri de ultima ora</a> zi de zi Smile
Mike on 4/2/2012 11:04 PM Hi  terrific blog
Website Development Company in Cleveland United States on 4/27/2012 7:34 AM Thanks for the post with the valuable tutorial....

Add comment




  Country flag
biuquote
  • Comment
  • Preview
Loading